|
@@ -111,59 +111,77 @@ func parsePlugins(pluginList []interface{}) ([]*PluginConfig, error) {
|
|
|
return plugins, nil
|
|
return plugins, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (c *Config) getInterface(ver protocolVersion) (string, error) {
|
|
|
|
|
- if err := protoVersionCheck(ver); err != nil {
|
|
|
|
|
- return "", err
|
|
|
|
|
- }
|
|
|
|
|
- directive := fmt.Sprintf("server%d.interface", ver)
|
|
|
|
|
- if exists := c.v.Get(directive); exists == nil {
|
|
|
|
|
- return "", ConfigErrorFromString("dhcpv%d: missing `%s` directive", ver, directive)
|
|
|
|
|
|
|
+// BUG(Natolumin): listen specifications of the form `[ip6]%iface:port` or
|
|
|
|
|
+// `[ip6]%iface` are not supported, even though they are the default format of
|
|
|
|
|
+// the `ss` utility in linux. Use `[ip6%iface]:port` instead
|
|
|
|
|
+
|
|
|
|
|
+// splitHostPort splits an address of the form ip%zone:port into ip,zone and port.
|
|
|
|
|
+// It still returns if any of these are unset (unlike net.SplitHostPort which
|
|
|
|
|
+// returns an error if there is no port)
|
|
|
|
|
+func splitHostPort(hostport string) (ip string, zone string, port string, err error) {
|
|
|
|
|
+ ip, port, err = net.SplitHostPort(hostport)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ // Either there is no port, or a more serious error.
|
|
|
|
|
+ // Supply a synthetic port to differentiate cases
|
|
|
|
|
+ var altErr error
|
|
|
|
|
+ if ip, _, altErr = net.SplitHostPort(hostport + ":0"); altErr != nil {
|
|
|
|
|
+ // Invalid even with a fake port. Return the original error
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ err = nil
|
|
|
}
|
|
}
|
|
|
- ifname := c.v.GetString(directive)
|
|
|
|
|
- if ifname == "" {
|
|
|
|
|
- return "", ConfigErrorFromString("dhcpv%d: missing `%s` directive", ver, directive)
|
|
|
|
|
|
|
+ if i := strings.LastIndexByte(ip, '%'); i >= 0 {
|
|
|
|
|
+ ip, zone = ip[:i], ip[i+1:]
|
|
|
}
|
|
}
|
|
|
- return ifname, nil
|
|
|
|
|
|
|
+ return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) getListenAddress(ver protocolVersion) (*net.UDPAddr, error) {
|
|
func (c *Config) getListenAddress(ver protocolVersion) (*net.UDPAddr, error) {
|
|
|
if err := protoVersionCheck(ver); err != nil {
|
|
if err := protoVersionCheck(ver); err != nil {
|
|
|
return nil, err
|
|
return nil, err
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
addr := c.v.GetString(fmt.Sprintf("server%d.listen", ver))
|
|
addr := c.v.GetString(fmt.Sprintf("server%d.listen", ver))
|
|
|
- if addr == "" {
|
|
|
|
|
- // return default listener
|
|
|
|
|
- if ver == protocolV6 {
|
|
|
|
|
- return &net.UDPAddr{
|
|
|
|
|
- IP: net.IPv6unspecified,
|
|
|
|
|
- Port: dhcpv6.DefaultServerPort,
|
|
|
|
|
- }, nil
|
|
|
|
|
- }
|
|
|
|
|
- return &net.UDPAddr{
|
|
|
|
|
- IP: net.IPv4zero,
|
|
|
|
|
- Port: dhcpv4.ServerPort,
|
|
|
|
|
- }, nil
|
|
|
|
|
- }
|
|
|
|
|
- ipStr, portStr, err := net.SplitHostPort(addr)
|
|
|
|
|
|
|
+ ipStr, ifname, portStr, err := splitHostPort(addr)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return nil, ConfigErrorFromString("dhcpv%d: %v", ver, err)
|
|
return nil, ConfigErrorFromString("dhcpv%d: %v", ver, err)
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
ip := net.ParseIP(ipStr)
|
|
ip := net.ParseIP(ipStr)
|
|
|
|
|
+ if ipStr == "" {
|
|
|
|
|
+ switch ver {
|
|
|
|
|
+ case protocolV4:
|
|
|
|
|
+ ip = net.IPv4zero
|
|
|
|
|
+ case protocolV6:
|
|
|
|
|
+ ip = net.IPv6unspecified
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
if ip == nil {
|
|
if ip == nil {
|
|
|
- return nil, ConfigErrorFromString("dhcpv%d: invalid IP address in `listen` directive", ver)
|
|
|
|
|
|
|
+ return nil, ConfigErrorFromString("dhcpv%d: invalid IP address in `listen` directive: %s", ver, ipStr)
|
|
|
}
|
|
}
|
|
|
- if ver == protocolV6 && ip.To4() != nil {
|
|
|
|
|
- return nil, ConfigErrorFromString("dhcpv%d: not a valid IPv6 address in `listen` directive", ver)
|
|
|
|
|
- } else if ver == protocolV4 && ip.To4() == nil {
|
|
|
|
|
- return nil, ConfigErrorFromString("dhcpv%d: not a valid IPv4 address in `listen` directive", ver)
|
|
|
|
|
|
|
+ if ip4 := ip.To4(); (ver == protocolV6 && ip4 != nil) || (ver == protocolV4 && ip4 == nil) {
|
|
|
|
|
+ return nil, ConfigErrorFromString("dhcpv%d: not a valid IPv%d address in `listen` directive", ver, ver)
|
|
|
}
|
|
}
|
|
|
- port, err := strconv.Atoi(portStr)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return nil, ConfigErrorFromString("dhcpv%d: invalid `listen` port", ver)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ var port int
|
|
|
|
|
+ if portStr == "" {
|
|
|
|
|
+ switch ver {
|
|
|
|
|
+ case protocolV4:
|
|
|
|
|
+ port = dhcpv4.ServerPort
|
|
|
|
|
+ case protocolV6:
|
|
|
|
|
+ port = dhcpv6.DefaultServerPort
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ port, err = strconv.Atoi(portStr)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, ConfigErrorFromString("dhcpv%d: invalid `listen` port", ver)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
listener := net.UDPAddr{
|
|
listener := net.UDPAddr{
|
|
|
IP: ip,
|
|
IP: ip,
|
|
|
Port: port,
|
|
Port: port,
|
|
|
|
|
+ Zone: ifname,
|
|
|
}
|
|
}
|
|
|
return &listener, nil
|
|
return &listener, nil
|
|
|
}
|
|
}
|
|
@@ -187,10 +205,6 @@ func (c *Config) parseConfig(ver protocolVersion) error {
|
|
|
// it is valid to have no server configuration defined
|
|
// it is valid to have no server configuration defined
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
- ifname, err := c.getInterface(ver)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
listenAddr, err := c.getListenAddress(ver)
|
|
listenAddr, err := c.getListenAddress(ver)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return err
|
|
return err
|
|
@@ -198,6 +212,7 @@ func (c *Config) parseConfig(ver protocolVersion) error {
|
|
|
if listenAddr == nil {
|
|
if listenAddr == nil {
|
|
|
// no listener is configured, so `c.Server6` (or `c.Server4` if v4)
|
|
// no listener is configured, so `c.Server6` (or `c.Server4` if v4)
|
|
|
// will stay nil.
|
|
// will stay nil.
|
|
|
|
|
+ log.Warnf("DHCPv%d: server%d present but no listen address defined. The server will not be started", ver, ver)
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
// read plugin configuration
|
|
// read plugin configuration
|
|
@@ -210,7 +225,7 @@ func (c *Config) parseConfig(ver protocolVersion) error {
|
|
|
}
|
|
}
|
|
|
sc := ServerConfig{
|
|
sc := ServerConfig{
|
|
|
Listener: listenAddr,
|
|
Listener: listenAddr,
|
|
|
- Interface: ifname,
|
|
|
|
|
|
|
+ Interface: listenAddr.Zone,
|
|
|
Plugins: plugins,
|
|
Plugins: plugins,
|
|
|
}
|
|
}
|
|
|
if ver == protocolV6 {
|
|
if ver == protocolV6 {
|