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  }