router7/internal/netconfig/netconfig.go

737 lines
19 KiB
Go
Raw Normal View History

2018-06-28 13:39:48 +02:00
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2018-06-25 20:12:51 +02:00
// Package netconfig implements network configuration (interfaces, addresses, firewall rules, …).
2018-05-27 17:30:42 +02:00
package netconfig
import (
"encoding/json"
"fmt"
"io/ioutil"
"net"
"os"
2018-05-27 17:30:42 +02:00
"path/filepath"
"regexp"
2018-05-27 17:30:42 +02:00
"strconv"
"strings"
"syscall"
2018-05-27 17:30:42 +02:00
2018-06-04 10:01:09 +02:00
"github.com/google/nftables"
2018-06-05 08:51:51 +02:00
"github.com/google/nftables/binaryutil"
2018-06-04 10:01:09 +02:00
"github.com/google/nftables/expr"
2018-05-27 17:30:42 +02:00
"github.com/vishvananda/netlink"
2018-06-05 08:51:51 +02:00
"golang.org/x/sys/unix"
2018-05-27 17:30:42 +02:00
2018-07-09 08:54:04 +02:00
"github.com/rtr7/router7/internal/dhcp4"
"github.com/rtr7/router7/internal/dhcp6"
"github.com/rtr7/router7/internal/notify"
"github.com/rtr7/router7/internal/teelogger"
2018-05-27 17:30:42 +02:00
)
2018-06-03 20:47:11 +02:00
var log = teelogger.NewConsole()
2018-05-27 17:30:42 +02:00
func subnetMaskSize(mask string) (int, error) {
parts := strings.Split(mask, ".")
if got, want := len(parts), 4; got != want {
return 0, fmt.Errorf("unexpected number of parts in subnet mask %q: got %d, want %d", mask, got, want)
}
numeric := make([]byte, len(parts))
for idx, part := range parts {
i, err := strconv.ParseUint(part, 0, 8)
if err != nil {
return 0, err
}
numeric[idx] = byte(i)
}
ones, _ := net.IPv4Mask(numeric[0], numeric[1], numeric[2], numeric[3]).Size()
return ones, nil
}
func applyDhcp4(dir string) error {
2018-05-27 17:30:42 +02:00
b, err := ioutil.ReadFile(filepath.Join(dir, "dhcp4/wire/lease.json"))
if err != nil {
if os.IsNotExist(err) {
return nil // dhcp4 might not have obtained a lease yet
}
2018-05-27 17:30:42 +02:00
return err
}
var got dhcp4.Config
if err := json.Unmarshal(b, &got); err != nil {
return err
}
link, err := netlink.LinkByName("uplink0")
2018-05-27 17:30:42 +02:00
if err != nil {
return err
}
if got.SubnetMask == "" {
return fmt.Errorf("invalid DHCP lease: no subnet mask present")
}
2018-05-27 17:30:42 +02:00
subnetSize, err := subnetMaskSize(got.SubnetMask)
if err != nil {
return err
}
addr, err := netlink.ParseAddr(fmt.Sprintf("%s/%d", got.ClientIP, subnetSize))
if err != nil {
return err
}
h, err := netlink.NewHandle()
if err != nil {
return fmt.Errorf("netlink.NewHandle: %v", err)
}
defer h.Delete()
2018-06-04 10:01:09 +02:00
if err := h.AddrReplace(link, addr); err != nil {
return fmt.Errorf("AddrReplace(%v): %v", addr, err)
2018-05-27 17:30:42 +02:00
}
// from include/uapi/linux/rtnetlink.h
const (
RTPROT_STATIC = 4
RTPROT_DHCP = 16
)
2018-06-12 09:29:53 +02:00
if err := h.RouteReplace(&netlink.Route{
2018-05-27 17:30:42 +02:00
LinkIndex: link.Attrs().Index,
Dst: &net.IPNet{
IP: net.ParseIP(got.Router),
Mask: net.CIDRMask(32, 32),
},
Src: net.ParseIP(got.ClientIP),
Scope: netlink.SCOPE_LINK,
Protocol: RTPROT_DHCP,
}); err != nil {
2018-06-12 09:29:53 +02:00
return fmt.Errorf("RouteReplace(router): %v", err)
2018-05-27 17:30:42 +02:00
}
2018-06-12 09:29:53 +02:00
if err := h.RouteReplace(&netlink.Route{
2018-05-27 17:30:42 +02:00
LinkIndex: link.Attrs().Index,
Dst: &net.IPNet{
IP: net.ParseIP("0.0.0.0"),
Mask: net.CIDRMask(0, 32),
},
Gw: net.ParseIP(got.Router),
Src: net.ParseIP(got.ClientIP),
Protocol: RTPROT_DHCP,
}); err != nil {
2018-06-12 09:29:53 +02:00
return fmt.Errorf("RouteReplace(default): %v", err)
2018-05-27 17:30:42 +02:00
}
return nil
}
func applyDhcp6(dir string) error {
2018-05-27 17:30:42 +02:00
b, err := ioutil.ReadFile(filepath.Join(dir, "dhcp6/wire/lease.json"))
if err != nil {
if os.IsNotExist(err) {
return nil // dhcp6 might not have obtained a lease yet
}
2018-05-27 17:30:42 +02:00
return err
}
var got dhcp6.Config
if err := json.Unmarshal(b, &got); err != nil {
return err
}
link, err := netlink.LinkByName("lan0")
2018-05-27 17:30:42 +02:00
if err != nil {
return err
}
for _, prefix := range got.Prefixes {
// pick the first address of the prefix, e.g. address 2a02:168:4a00::1
// for prefix 2a02:168:4a00::/48
prefix.IP[len(prefix.IP)-1] = 1
2018-05-28 09:53:54 +02:00
// Use the first /64 subnet within larger prefixes
if ones, bits := prefix.Mask.Size(); ones < 64 {
prefix.Mask = net.CIDRMask(64, bits)
}
2018-05-27 17:30:42 +02:00
addr, err := netlink.ParseAddr(prefix.String())
if err != nil {
return err
}
if err := netlink.AddrReplace(link, addr); err != nil {
return fmt.Errorf("AddrReplace(%v): %v", addr, err)
2018-05-27 17:30:42 +02:00
}
}
return nil
}
type InterfaceDetails struct {
HardwareAddr string `json:"hardware_addr"` // e.g. dc:9b:9c:ee:72:fd
SpoofHardwareAddr string `json:"spoof_hardware_addr"` // e.g. dc:9b:9c:ee:72:fd
Name string `json:"name"` // e.g. uplink0, or lan0
Addr string `json:"addr"` // e.g. 192.168.42.1/24
2018-05-27 17:30:42 +02:00
}
type InterfaceConfig struct {
Interfaces []InterfaceDetails `json:"interfaces"`
}
// LinkAddress returns the IP address configured for the interface ifname in
// interfaces.json.
func LinkAddress(dir, ifname string) (net.IP, error) {
fn := filepath.Join(dir, "interfaces.json")
b, err := ioutil.ReadFile(fn)
if err != nil {
return nil, err
}
var cfg InterfaceConfig
if err := json.Unmarshal(b, &cfg); err != nil {
return nil, err
}
for _, details := range cfg.Interfaces {
if details.Name != ifname {
continue
}
ip, _, err := net.ParseCIDR(details.Addr)
return ip, err
}
return nil, fmt.Errorf("%s does not configure interface %q", fn, ifname)
}
2018-06-03 20:47:11 +02:00
func applyInterfaces(dir, root string) error {
2018-05-27 17:30:42 +02:00
b, err := ioutil.ReadFile(filepath.Join(dir, "interfaces.json"))
if err != nil {
return err
}
var cfg InterfaceConfig
if err := json.Unmarshal(b, &cfg); err != nil {
return err
}
byHardwareAddr := make(map[string]InterfaceDetails)
for _, details := range cfg.Interfaces {
byHardwareAddr[details.HardwareAddr] = details
if spoof := details.SpoofHardwareAddr; spoof != "" {
byHardwareAddr[spoof] = details
}
2018-05-27 17:30:42 +02:00
}
links, err := netlink.LinkList()
for _, l := range links {
attr := l.Attrs()
// TODO: prefix log line with details about the interface.
// link &{LinkAttrs:{Index:2 MTU:1500 TxQLen:1000 Name:eth0 HardwareAddr:00:0d:b9:49:70:18 Flags:broadcast|multicast RawFlags:4098 ParentIndex:0 MasterIndex:0 Namespace:<nil> Alias: Statistics:0xc4200f45f8 Promisc:0 Xdp:0xc4200ca180 EncapType:ether Protinfo:<nil> OperState:down NetNsID:0 NumTxQueues:0 NumRxQueues:0 Vfs:[]}}, attr &{Index:2 MTU:1500 TxQLen:1000 Name:eth0 HardwareAddr:00:0d:b9:49:70:18 Flags:broadcast|multicast RawFlags:4098 ParentIndex:0 MasterIndex:0 Namespace:<nil> Alias: Statistics:0xc4200f45f8 Promisc:0 Xdp:0xc4200ca180 EncapType:ether Protinfo:<nil> OperState:down NetNsID:0 NumTxQueues:0 NumRxQueues:0 Vfs:[]}
addr := attr.HardwareAddr.String()
details, ok := byHardwareAddr[addr]
2018-05-27 17:30:42 +02:00
if !ok {
if addr == "" {
continue // not a configurable interface (e.g. sit0)
}
log.Printf("no config for hardwareattr %s", addr)
2018-05-27 17:30:42 +02:00
continue
}
log.Printf("apply details %+v", details)
if attr.Name != details.Name {
if err := netlink.LinkSetName(l, details.Name); err != nil {
return fmt.Errorf("LinkSetName(%q): %v", details.Name, err)
}
attr.Name = details.Name
}
if spoof := details.SpoofHardwareAddr; spoof != "" {
hwaddr, err := net.ParseMAC(spoof)
if err != nil {
return fmt.Errorf("ParseMAC(%q): %v", spoof, err)
}
if err := netlink.LinkSetHardwareAddr(l, hwaddr); err != nil {
return fmt.Errorf("LinkSetHardwareAddr(%v): %v", hwaddr, err)
}
}
2018-05-27 17:30:42 +02:00
if attr.OperState != netlink.OperUp {
// Set the interface to up, which is required by all other configuration.
if err := netlink.LinkSetUp(l); err != nil {
return fmt.Errorf("LinkSetUp(%s): %v", attr.Name, err)
}
}
if details.Addr != "" {
addr, err := netlink.ParseAddr(details.Addr)
if err != nil {
return fmt.Errorf("ParseAddr(%q): %v", details.Addr, err)
}
if err := netlink.AddrReplace(l, addr); err != nil {
return fmt.Errorf("AddrReplace(%s, %v): %v", attr.Name, addr, err)
}
2018-06-03 20:47:11 +02:00
if details.Name == "lan0" {
b := []byte("nameserver " + addr.IP.String() + "\n")
2018-06-22 17:59:23 +02:00
fn := filepath.Join(root, "tmp", "resolv.conf")
2018-06-03 20:47:11 +02:00
if err := os.Remove(fn); err != nil && !os.IsNotExist(err) {
return err
}
if err := ioutil.WriteFile(fn, b, 0644); err != nil {
return err
}
}
2018-05-27 17:30:42 +02:00
}
}
return nil
}
2018-06-05 08:48:30 +02:00
func ifname(n string) []byte {
b := make([]byte, 16)
copy(b, []byte(n+"\x00"))
return b
}
func portForwardExpr(proto uint8, portMin, portMax uint16, dest net.IP, dportMin, dportMax uint16) []expr.Any {
var cmp []expr.Any
if portMin == portMax {
cmp = []expr.Any{
// [ cmp eq reg 1 0x0000e60f ]
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: binaryutil.BigEndian.PutUint16(portMin),
},
}
} else {
cmp = []expr.Any{
// [ cmp gte reg 1 0x0000e60f ]
&expr.Cmp{
Op: expr.CmpOpGte,
Register: 1,
Data: binaryutil.BigEndian.PutUint16(portMin),
},
// [ cmp lte reg 1 0x0000fa0f ]
&expr.Cmp{
Op: expr.CmpOpLte,
Register: 1,
Data: binaryutil.BigEndian.PutUint16(portMax),
},
}
}
ex := []expr.Any{
2018-06-05 08:51:51 +02:00
// [ meta load iifname => reg 1 ]
&expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},
// [ cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000 ]
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: ifname("uplink0"),
},
// [ meta load l4proto => reg 1 ]
&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},
// [ cmp eq reg 1 0x00000006 ]
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: []byte{proto},
2018-06-05 08:51:51 +02:00
},
// [ payload load 2b @ transport header + 2 => reg 1 ]
&expr.Payload{
DestRegister: 1,
Base: expr.PayloadBaseTransportHeader,
Offset: 2, // TODO
Len: 2, // TODO
},
}
ex = append(ex, cmp...)
ex = append(ex,
2018-06-05 08:51:51 +02:00
// [ immediate reg 1 0x0217a8c0 ]
&expr.Immediate{
Register: 1,
Data: dest.To4(),
},
)
if dportMin == dportMax {
ex = append(ex,
// [ immediate reg 2 0x0000f00f ]
&expr.Immediate{
Register: 2,
Data: binaryutil.BigEndian.PutUint16(dportMin),
},
// [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 ]
&expr.NAT{
Type: expr.NATTypeDestNAT,
Family: unix.NFPROTO_IPV4,
RegAddrMin: 1,
RegProtoMin: 2,
},
)
} else {
ex = append(ex,
// [ immediate reg 2 0x0000e60f ]
&expr.Immediate{
Register: 2,
Data: binaryutil.BigEndian.PutUint16(dportMin),
},
// [ immediate reg 3 0x0000fa0f ]
&expr.Immediate{
Register: 3,
Data: binaryutil.BigEndian.PutUint16(dportMax),
},
// [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 3 ]
&expr.NAT{
Type: expr.NATTypeDestNAT,
Family: unix.NFPROTO_IPV4,
RegAddrMin: 1,
RegProtoMin: 2,
RegProtoMax: 3,
},
)
2018-06-05 08:51:51 +02:00
}
return ex
2018-06-05 08:51:51 +02:00
}
type portForwarding struct {
Proto string `json:"proto"` // e.g. “tcp” (or “tcp,udp”)
Port string `json:"port"` // e.g. “8080” (or “8080-8090”)
DestAddr string `json:"dest_addr"` // e.g. “192.168.42.2”
DestPort string `json:"dest_port"` // e.g. “80” (or “80-90”)
2018-06-05 08:51:51 +02:00
}
type portForwardings struct {
Forwardings []portForwarding `json:"forwardings"`
}
var rangeRe = regexp.MustCompile(`^([0-9]+)(?:-([0-9]+))?$`)
func parsePort(p string) (min uint16, max uint16, _ error) {
matches := rangeRe.FindStringSubmatch(p)
if len(matches) == 0 {
return 0, 0, fmt.Errorf("malformed port %q, expected port number (e.g. 8080) or port range (e.g. 8080-8090)", p)
}
min64, err := strconv.ParseUint(matches[1], 0, 16)
if err != nil {
return 0, 0, fmt.Errorf("ParseInt(%q): %v", matches[1], err)
}
max64 := min64
if matches[2] != "" {
max64, err = strconv.ParseUint(matches[2], 0, 16)
if err != nil {
return 0, 0, fmt.Errorf("ParseInt(%q): %v", matches[2], err)
}
}
return uint16(min64), uint16(max64), nil
}
2018-06-05 08:51:51 +02:00
func applyPortForwardings(dir string, c *nftables.Conn, nat *nftables.Table, prerouting *nftables.Chain) error {
b, err := ioutil.ReadFile(filepath.Join(dir, "portforwardings.json"))
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
var cfg portForwardings
if err := json.Unmarshal(b, &cfg); err != nil {
return err
}
for _, fw := range cfg.Forwardings {
for _, proto := range strings.Split(fw.Proto, ",") {
var p uint8
switch proto {
case "", "tcp":
p = unix.IPPROTO_TCP
case "udp":
p = unix.IPPROTO_UDP
default:
return fmt.Errorf(`unknown proto %q, expected "tcp" or "udp"`, proto)
}
min, max, err := parsePort(fw.Port)
if err != nil {
return err
}
dmin, dmax, err := parsePort(fw.DestPort)
if err != nil {
return err
}
c.AddRule(&nftables.Rule{
Table: nat,
Chain: prerouting,
Exprs: portForwardExpr(p, min, max, net.ParseIP(fw.DestAddr), dmin, dmax),
})
}
2018-06-05 08:51:51 +02:00
}
return nil
}
// DefaultCounterObj is overridden while testing
var DefaultCounterObj = &nftables.CounterObj{}
func getCounterObj(c *nftables.Conn, o *nftables.CounterObj) *nftables.CounterObj {
objs, err := c.GetObj(o)
if err != nil {
o.Bytes = DefaultCounterObj.Bytes
o.Packets = DefaultCounterObj.Packets
return o
}
{
// TODO: remove this workaround once travis has workers with a newer kernel
// than its current Ubuntu trusty kernel (Linux 4.4.0):
var filtered []nftables.Obj
for _, obj := range objs {
co, ok := obj.(*nftables.CounterObj)
if !ok {
continue
}
if co.Table.Name != o.Table.Name {
continue
}
filtered = append(filtered, obj)
}
objs = filtered
}
if got, want := len(objs), 1; got != want {
log.Printf("could not carry counter values: unexpected number of objects in table %v: got %d, want %d", o.Table.Name, got, want)
o.Bytes = DefaultCounterObj.Bytes
o.Packets = DefaultCounterObj.Packets
return o
}
if co, ok := objs[0].(*nftables.CounterObj); ok {
return co
}
o.Bytes = DefaultCounterObj.Bytes
o.Packets = DefaultCounterObj.Packets
return o
}
2018-06-05 08:51:51 +02:00
func applyFirewall(dir string) error {
2018-06-04 10:01:09 +02:00
c := &nftables.Conn{}
c.FlushRuleset()
2018-06-04 10:01:09 +02:00
nat := c.AddTable(&nftables.Table{
Family: nftables.TableFamilyIPv4,
Name: "nat",
})
2018-06-05 08:51:51 +02:00
prerouting := c.AddChain(&nftables.Chain{
2018-06-04 10:01:09 +02:00
Name: "prerouting",
Hooknum: nftables.ChainHookPrerouting,
Priority: nftables.ChainPriorityFilter,
Table: nat,
Type: nftables.ChainTypeNAT,
})
postrouting := c.AddChain(&nftables.Chain{
Name: "postrouting",
Hooknum: nftables.ChainHookPostrouting,
Priority: nftables.ChainPriorityNATSource,
Table: nat,
Type: nftables.ChainTypeNAT,
})
c.AddRule(&nftables.Rule{
Table: nat,
Chain: postrouting,
Exprs: []expr.Any{
2018-06-05 08:48:30 +02:00
// meta load oifname => reg 1
&expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},
// cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000
2018-06-04 10:01:09 +02:00
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
2018-06-05 08:48:30 +02:00
Data: ifname("uplink0"),
2018-06-04 10:01:09 +02:00
},
// masq
&expr.Masq{},
},
})
2018-05-27 17:30:42 +02:00
2018-06-05 08:51:51 +02:00
if err := applyPortForwardings(dir, c, nat, prerouting); err != nil {
return err
}
filter4 := c.AddTable(&nftables.Table{
Family: nftables.TableFamilyIPv4,
Name: "filter",
})
filter6 := c.AddTable(&nftables.Table{
Family: nftables.TableFamilyIPv6,
Name: "filter",
})
for _, filter := range []*nftables.Table{filter4, filter6} {
forward := c.AddChain(&nftables.Chain{
Name: "forward",
Hooknum: nftables.ChainHookForward,
Priority: nftables.ChainPriorityFilter,
Table: filter,
Type: nftables.ChainTypeFilter,
})
c.AddRule(&nftables.Rule{
Table: filter,
Chain: forward,
Exprs: []expr.Any{
// [ meta load oifname => reg 1 ]
&expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},
// [ cmp eq reg 1 0x30707070 0x00000000 0x00000000 0x00000000 ]
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: ifname("uplink0"),
},
// [ meta load l4proto => reg 1 ]
&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},
// [ cmp eq reg 1 0x00000006 ]
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: []byte{unix.IPPROTO_TCP},
},
// [ payload load 1b @ transport header + 13 => reg 1 ]
&expr.Payload{
DestRegister: 1,
Base: expr.PayloadBaseTransportHeader,
Offset: 13, // TODO
Len: 1, // TODO
},
// [ bitwise reg 1 = (reg=1 & 0x00000002 ) ^ 0x00000000 ]
&expr.Bitwise{
DestRegister: 1,
SourceRegister: 1,
Len: 1,
Mask: []byte{0x02},
Xor: []byte{0x00},
},
// [ cmp neq reg 1 0x00000000 ]
&expr.Cmp{
Op: expr.CmpOpNeq,
Register: 1,
Data: []byte{0x00},
},
// [ rt load tcpmss => reg 1 ]
&expr.Rt{
Register: 1,
Key: expr.RtTCPMSS,
},
// [ byteorder reg 1 = hton(reg 1, 2, 2) ]
&expr.Byteorder{
DestRegister: 1,
SourceRegister: 1,
Op: expr.ByteorderHton,
Len: 2,
Size: 2,
},
// [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
&expr.Exthdr{
SourceRegister: 1,
Type: 2, // TODO
Offset: 2,
Len: 2,
Op: expr.ExthdrOpTcpopt,
},
},
})
counterObj := getCounterObj(c, &nftables.CounterObj{
Table: filter,
Name: "fwded",
})
counter := c.AddObj(counterObj).(*nftables.CounterObj)
const NFT_OBJECT_COUNTER = 1 // TODO: get into x/sys/unix
c.AddRule(&nftables.Rule{
Table: filter,
Chain: forward,
Exprs: []expr.Any{
// [ counter name fwded ]
&expr.Objref{
Type: NFT_OBJECT_COUNTER,
Name: counter.Name,
},
},
})
}
2018-06-04 10:01:09 +02:00
return c.Flush()
2018-05-27 17:30:42 +02:00
}
func applySysctl() error {
if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte("1"), 0644); err != nil {
2018-05-28 09:53:54 +02:00
return fmt.Errorf("sysctl(net.ipv4.ip_forward=1): %v", err)
}
if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte("1"), 0644); err != nil {
return fmt.Errorf("sysctl(net.ipv6.conf.all.forwarding=1): %v", err)
}
if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/uplink0/accept_ra", []byte("2"), 0644); err != nil {
return fmt.Errorf("sysctl(net.ipv6.conf.uplink0.accept_ra=2): %v", err)
2018-05-27 17:30:42 +02:00
}
2018-05-28 09:53:54 +02:00
2018-05-27 17:30:42 +02:00
return nil
}
2018-06-03 20:47:11 +02:00
func Apply(dir, root string) error {
2018-05-28 09:53:54 +02:00
// TODO: split into two parts: delay the up until later
2018-06-03 20:47:11 +02:00
if err := applyInterfaces(dir, root); err != nil {
return fmt.Errorf("interfaces: %v", err)
2018-05-27 17:30:42 +02:00
}
var firstErr error
if err := applyDhcp4(dir); err != nil {
if firstErr == nil {
firstErr = fmt.Errorf("dhcp4: %v", err)
} else {
log.Printf("cannot apply dhcp4 lease: %v", err)
}
2018-05-27 17:30:42 +02:00
}
if err := applyDhcp6(dir); err != nil {
if firstErr == nil {
firstErr = fmt.Errorf("dhcp6: %v", err)
} else {
log.Printf("cannot apply dhcp6 lease: %v", err)
}
2018-05-27 17:30:42 +02:00
}
for _, process := range []string{
2018-06-27 19:44:39 +02:00
"dyndns", // depends on the public IPv4 address
"dnsd", // listens on private IPv4/IPv6
"diagd", // listens on private IPv4/IPv6
"backupd", // listens on private IPv4/IPv6
"captured", // listens on private IPv4/IPv6
} {
if err := notify.Process("/user/"+process, syscall.SIGUSR1); err != nil {
log.Printf("notifying %s: %v", process, err)
}
}
2018-05-27 17:30:42 +02:00
if err := applySysctl(); err != nil {
if firstErr == nil {
firstErr = fmt.Errorf("sysctl: %v", err)
} else {
log.Printf("cannot apply sysctl config: %v", err)
}
2018-05-27 17:30:42 +02:00
}
2018-06-05 08:51:51 +02:00
if err := applyFirewall(dir); err != nil {
return fmt.Errorf("firewall: %v", err)
2018-05-27 17:30:42 +02:00
}
return firstErr
2018-05-27 17:30:42 +02:00
}