github.com/codemac/docker@v1.2.1-0.20150518222241-6a18412d5b9c/pkg/iptables/firewalld.go (about) 1 package iptables 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/Sirupsen/logrus" 8 "github.com/godbus/dbus" 9 ) 10 11 type IPV string 12 13 const ( 14 Iptables IPV = "ipv4" 15 Ip6tables IPV = "ipv6" 16 Ebtables IPV = "eb" 17 ) 18 const ( 19 dbusInterface = "org.fedoraproject.FirewallD1" 20 dbusPath = "/org/fedoraproject/FirewallD1" 21 ) 22 23 // Conn is a connection to firewalld dbus endpoint. 24 type Conn struct { 25 sysconn *dbus.Conn 26 sysobj *dbus.Object 27 signal chan *dbus.Signal 28 } 29 30 var ( 31 connection *Conn 32 firewalldRunning bool // is Firewalld service running 33 onReloaded []*func() // callbacks when Firewalld has been reloaded 34 ) 35 36 func FirewalldInit() error { 37 var err error 38 39 if connection, err = newConnection(); err != nil { 40 return fmt.Errorf("Failed to connect to D-Bus system bus: %v", err) 41 } 42 if connection != nil { 43 go signalHandler() 44 } 45 46 firewalldRunning = checkRunning() 47 return nil 48 } 49 50 // New() establishes a connection to the system bus. 51 func newConnection() (*Conn, error) { 52 c := new(Conn) 53 if err := c.initConnection(); err != nil { 54 return nil, err 55 } 56 57 return c, nil 58 } 59 60 // Innitialize D-Bus connection. 61 func (c *Conn) initConnection() error { 62 var err error 63 64 c.sysconn, err = dbus.SystemBus() 65 if err != nil { 66 return err 67 } 68 69 // This never fails, even if the service is not running atm. 70 c.sysobj = c.sysconn.Object(dbusInterface, dbus.ObjectPath(dbusPath)) 71 72 rule := fmt.Sprintf("type='signal',path='%s',interface='%s',sender='%s',member='Reloaded'", 73 dbusPath, dbusInterface, dbusInterface) 74 c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule) 75 76 rule = fmt.Sprintf("type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',path='/org/freedesktop/DBus',sender='org.freedesktop.DBus',arg0='%s'", 77 dbusInterface) 78 c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule) 79 80 c.signal = make(chan *dbus.Signal, 10) 81 c.sysconn.Signal(c.signal) 82 83 return nil 84 } 85 86 func signalHandler() { 87 for signal := range connection.signal { 88 if strings.Contains(signal.Name, "NameOwnerChanged") { 89 firewalldRunning = checkRunning() 90 dbusConnectionChanged(signal.Body) 91 } else if strings.Contains(signal.Name, "Reloaded") { 92 reloaded() 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 return false 149 } 150 151 // Firewalld's passthrough method simply passes args through to iptables/ip6tables 152 func Passthrough(ipv IPV, args ...string) ([]byte, error) { 153 var output string 154 logrus.Debugf("Firewalld passthrough: %s, %s", ipv, args) 155 if err := connection.sysobj.Call(dbusInterface+".direct.passthrough", 0, ipv, args).Store(&output); err != nil { 156 return nil, err 157 } 158 return []byte(output), nil 159 }