github.com/guilhermebr/docker@v1.4.2-0.20150428121140-67da055cebca/pkg/iptables/firewalld.go (about) 1 package iptables 2 3 import ( 4 "fmt" 5 "github.com/Sirupsen/logrus" 6 "github.com/godbus/dbus" 7 "strings" 8 ) 9 10 type IPV string 11 12 const ( 13 Iptables IPV = "ipv4" 14 Ip6tables IPV = "ipv6" 15 Ebtables IPV = "eb" 16 ) 17 const ( 18 dbusInterface = "org.fedoraproject.FirewallD1" 19 dbusPath = "/org/fedoraproject/FirewallD1" 20 ) 21 22 // Conn is a connection to firewalld dbus endpoint. 23 type Conn struct { 24 sysconn *dbus.Conn 25 sysobj *dbus.Object 26 signal chan *dbus.Signal 27 } 28 29 var ( 30 connection *Conn 31 firewalldRunning bool // is Firewalld service running 32 onReloaded []*func() // callbacks when Firewalld has been reloaded 33 ) 34 35 func FirewalldInit() { 36 var err error 37 38 connection, err = newConnection() 39 40 if err != nil { 41 logrus.Errorf("Failed to connect to D-Bus system bus: %s", err) 42 } 43 44 firewalldRunning = checkRunning() 45 } 46 47 // New() establishes a connection to the system bus. 48 func newConnection() (*Conn, error) { 49 c := new(Conn) 50 if err := c.initConnection(); err != nil { 51 return nil, err 52 } 53 54 return c, nil 55 } 56 57 // Innitialize D-Bus connection. 58 func (c *Conn) initConnection() error { 59 var err error 60 61 c.sysconn, err = dbus.SystemBus() 62 if err != nil { 63 return err 64 } 65 66 // This never fails, even if the service is not running atm. 67 c.sysobj = c.sysconn.Object(dbusInterface, dbus.ObjectPath(dbusPath)) 68 69 rule := fmt.Sprintf("type='signal',path='%s',interface='%s',sender='%s',member='Reloaded'", 70 dbusPath, dbusInterface, dbusInterface) 71 c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule) 72 73 rule = fmt.Sprintf("type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',path='/org/freedesktop/DBus',sender='org.freedesktop.DBus',arg0='%s'", 74 dbusInterface) 75 c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule) 76 77 c.signal = make(chan *dbus.Signal, 10) 78 c.sysconn.Signal(c.signal) 79 go signalHandler() 80 81 return nil 82 } 83 84 func signalHandler() { 85 if connection != nil { 86 for signal := range connection.signal { 87 if strings.Contains(signal.Name, "NameOwnerChanged") { 88 firewalldRunning = checkRunning() 89 dbusConnectionChanged(signal.Body) 90 } else if strings.Contains(signal.Name, "Reloaded") { 91 reloaded() 92 } 93 } 94 } 95 } 96 97 func dbusConnectionChanged(args []interface{}) { 98 name := args[0].(string) 99 old_owner := args[1].(string) 100 new_owner := args[2].(string) 101 102 if name != dbusInterface { 103 return 104 } 105 106 if len(new_owner) > 0 { 107 connectionEstablished() 108 } else if len(old_owner) > 0 { 109 connectionLost() 110 } 111 } 112 113 func connectionEstablished() { 114 reloaded() 115 } 116 117 func connectionLost() { 118 // Doesn't do anything for now. Libvirt also doesn't react to this. 119 } 120 121 // call all callbacks 122 func reloaded() { 123 for _, pf := range onReloaded { 124 (*pf)() 125 } 126 } 127 128 // add callback 129 func OnReloaded(callback func()) { 130 for _, pf := range onReloaded { 131 if pf == &callback { 132 return 133 } 134 } 135 onReloaded = append(onReloaded, &callback) 136 } 137 138 // Call some remote method to see whether the service is actually running. 139 func checkRunning() bool { 140 var zone string 141 var err error 142 143 if connection != nil { 144 err = connection.sysobj.Call(dbusInterface+".getDefaultZone", 0).Store(&zone) 145 logrus.Infof("Firewalld running: %t", err == nil) 146 return err == nil 147 } 148 logrus.Info("Firewalld not running") 149 return false 150 } 151 152 // Firewalld's passthrough method simply passes args through to iptables/ip6tables 153 func Passthrough(ipv IPV, args ...string) ([]byte, error) { 154 var output string 155 156 logrus.Debugf("Firewalld passthrough: %s, %s", ipv, args) 157 err := connection.sysobj.Call(dbusInterface+".direct.passthrough", 0, ipv, args).Store(&output) 158 if output != "" { 159 logrus.Debugf("passthrough output: %s", output) 160 } 161 162 return []byte(output), err 163 }