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  }