5e167a6493
Firewalld [1] is a firewall managing daemon with D-Bus interface. What sort of problem are we trying to solve with this ? Firewalld internally also executes iptables/ip6tables to change firewall settings. It might happen on systems where both docker and firewalld are running concurrently, that both of them try to call iptables at the same time. The result is that the second one fails because the first one is holding a xtables lock. One workaround is to use --wait/-w option in both docker & firewalld when calling iptables. It's already been done in both upstreams:b315c380f4
b3b451d6f8
But it'd still be better if docker used firewalld when it's running. Other problem the firewalld support would solve is that iptables/firewalld service's restart flushes all firewall rules previously added by docker. See next patch for possible solution. This patch utilizes firewalld's D-Bus interface. If firewalld is running, we call direct.passthrough() [2] method instead of executing iptables directly. direct.passthrough() takes the same arguments as iptables tool itself and passes them through to iptables tool. It might be better to use other methods, like direct.addChain and direct.addRule [3] so it'd be more intergrated with firewalld, but that'd make the patch much bigger. If firewalld is not running, everything works as before. [1] http://www.firewalld.org/ [2] https://jpopelka.fedorapeople.org/firewalld/doc/firewalld.dbus.html#FirewallD1.direct.Methods.passthrough [3] https://jpopelka.fedorapeople.org/firewalld/doc/firewalld.dbus.html#FirewallD1.direct.Methods.addChain https://jpopelka.fedorapeople.org/firewalld/doc/firewalld.dbus.html#FirewallD1.direct.Methods.addRule Signed-off-by: Jiri Popelka <jpopelka@redhat.com>
94 lines
2 KiB
Go
94 lines
2 KiB
Go
package iptables
|
|
|
|
import (
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/godbus/dbus"
|
|
)
|
|
|
|
type IPV string
|
|
|
|
const (
|
|
Iptables IPV = "ipv4"
|
|
Ip6tables IPV = "ipv6"
|
|
Ebtables IPV = "eb"
|
|
)
|
|
const (
|
|
dbusInterface = "org.fedoraproject.FirewallD1"
|
|
dbusPath = "/org/fedoraproject/FirewallD1"
|
|
)
|
|
|
|
// Conn is a connection to firewalld dbus endpoint.
|
|
type Conn struct {
|
|
sysconn *dbus.Conn
|
|
sysobj *dbus.Object
|
|
signal chan *dbus.Signal
|
|
}
|
|
|
|
var (
|
|
connection *Conn
|
|
firewalldRunning bool // is Firewalld service running
|
|
)
|
|
|
|
func FirewalldInit() {
|
|
var err error
|
|
|
|
connection, err = newConnection()
|
|
|
|
if err != nil {
|
|
logrus.Errorf("Failed to connect to D-Bus system bus: %s", err)
|
|
}
|
|
|
|
firewalldRunning = checkRunning()
|
|
}
|
|
|
|
// New() establishes a connection to the system bus.
|
|
func newConnection() (*Conn, error) {
|
|
c := new(Conn)
|
|
if err := c.initConnection(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// Innitialize D-Bus connection.
|
|
func (c *Conn) initConnection() error {
|
|
var err error
|
|
|
|
c.sysconn, err = dbus.SystemBus()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// This never fails, even if the service is not running atm.
|
|
c.sysobj = c.sysconn.Object(dbusInterface, dbus.ObjectPath(dbusPath))
|
|
|
|
return nil
|
|
}
|
|
|
|
// Call some remote method to see whether the service is actually running.
|
|
func checkRunning() bool {
|
|
var zone string
|
|
var err error
|
|
|
|
if connection != nil {
|
|
err = connection.sysobj.Call(dbusInterface+".getDefaultZone", 0).Store(&zone)
|
|
logrus.Infof("Firewalld running: %t", err == nil)
|
|
return err == nil
|
|
}
|
|
logrus.Info("Firewalld not running")
|
|
return false
|
|
}
|
|
|
|
// Firewalld's passthrough method simply passes args through to iptables/ip6tables
|
|
func Passthrough(ipv IPV, args ...string) ([]byte, error) {
|
|
var output string
|
|
|
|
logrus.Debugf("Firewalld passthrough: %s, %s", ipv, args)
|
|
err := connection.sysobj.Call(dbusInterface+".direct.passthrough", 0, ipv, args).Store(&output)
|
|
if output != "" {
|
|
logrus.Debugf("passthrough output: %s", output)
|
|
}
|
|
|
|
return []byte(output), err
|
|
}
|