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