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"
2018-06-03 20:35:41 +02:00
"os"
2018-05-27 17:30:42 +02:00
"path/filepath"
2018-06-14 22:25:39 +02:00
"regexp"
2018-05-27 17:30:42 +02:00
"strconv"
"strings"
2018-06-17 20:44:25 +02:00
"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
"router7/internal/dhcp4"
"router7/internal/dhcp6"
2018-06-17 20:44:25 +02:00
"router7/internal/notify"
2018-06-03 20:47:11 +02:00
"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
}
2018-06-03 20:35:41 +02:00
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 {
2018-06-02 17:38:17 +02:00
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
}
2018-06-03 20:35:41 +02:00
link , err := netlink . LinkByName ( "uplink0" )
2018-05-27 17:30:42 +02:00
if err != nil {
return err
}
2018-06-14 21:05:43 +02:00
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 )
}
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
}
2018-06-03 20:35:41 +02:00
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 {
2018-06-02 17:38:17 +02:00
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
}
2018-06-03 20:35:41 +02:00
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
}
2018-06-14 08:27:08 +02:00
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 {
2018-06-04 08:30:57 +02:00
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" `
}
2018-06-04 08:02:28 +02:00
// 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
2018-06-04 08:30:57 +02:00
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 ( )
2018-06-03 20:35:41 +02:00
// 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 {
2018-06-03 20:35:41 +02:00
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
}
2018-06-04 08:30:57 +02:00
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
}
2018-06-14 22:25:39 +02:00
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 ,
2018-06-14 21:05:43 +02:00
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
} ,
2018-06-14 22:25:39 +02:00
}
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 ( ) ,
} ,
2018-06-14 22:25:39 +02:00
)
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
}
2018-06-14 22:25:39 +02:00
return ex
2018-06-05 08:51:51 +02:00
}
type portForwarding struct {
2018-06-14 21:05:43 +02:00
Proto string ` json:"proto" ` // e.g. “tcp” (or “tcp,udp”)
2018-06-14 22:25:39 +02:00
Port string ` json:"port" ` // e.g. “8080” (or “8080-8090”)
2018-06-14 21:05:43 +02:00
DestAddr string ` json:"dest_addr" ` // e.g. “192.168.42.2”
2018-06-14 22:25:39 +02:00
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" `
}
2018-06-14 22:25:39 +02:00
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 {
2018-06-14 21:05:43 +02:00
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 )
}
2018-06-14 22:25:39 +02:00
min , max , err := parsePort ( fw . Port )
if err != nil {
return err
}
dmin , dmax , err := parsePort ( fw . DestPort )
if err != nil {
return err
}
2018-06-14 21:05:43 +02:00
c . AddRule ( & nftables . Rule {
Table : nat ,
Chain : prerouting ,
2018-06-14 22:25:39 +02:00
Exprs : portForwardExpr ( p , min , max , net . ParseIP ( fw . DestAddr ) , dmin , dmax ) ,
2018-06-14 21:05:43 +02:00
} )
}
2018-06-05 08:51:51 +02:00
}
return nil
}
2018-06-23 19:56:34 +02:00
// DefaultCounter is overridden while testing
var DefaultCounter expr . Counter
func getCounter ( c * nftables . Conn , table * nftables . Table , chain * nftables . Chain ) expr . Counter {
rules , err := c . GetRule ( table , chain )
if err != nil {
return DefaultCounter
}
if got , want := len ( rules ) , 1 ; got != want {
log . Printf ( "could not carry counter values: unexpected number of rules in table %v, chain %v: got %d, want %d" , table . Name , chain . Name , got , want )
return DefaultCounter
}
if got , want := len ( rules [ 0 ] . Exprs ) , 1 ; got != want {
log . Printf ( "could not carry counter values: unexpected number of exprs in rule 0 in table %v, chain %v: got %d, want %d" , table . Name , chain . Name , got , want )
return DefaultCounter
}
if ce , ok := rules [ 0 ] . Exprs [ 0 ] . ( * expr . Counter ) ; ok {
return * ce
}
return DefaultCounter
}
2018-06-05 08:51:51 +02:00
func applyFirewall ( dir string ) error {
2018-06-04 10:01:09 +02:00
c := & nftables . Conn { }
2018-06-14 08:27:08 +02:00
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
}
2018-06-23 19:56:34 +02:00
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 ,
} )
counter := getCounter ( c , filter , forward )
c . AddRule ( & nftables . Rule {
Table : filter ,
Chain : forward ,
Exprs : [ ] expr . Any {
// [ counter pkts 23 bytes 42 ]
& counter ,
} ,
} )
}
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 {
2018-06-03 20:35:41 +02:00
return fmt . Errorf ( "interfaces: %v" , err )
2018-05-27 17:30:42 +02:00
}
2018-06-02 17:36:36 +02:00
var firstErr error
2018-06-03 20:35:41 +02:00
if err := applyDhcp4 ( dir ) ; err != nil {
2018-06-14 18:28:40 +02:00
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
}
2018-06-03 20:35:41 +02:00
if err := applyDhcp6 ( dir ) ; err != nil {
2018-06-02 17:36:36 +02:00
if firstErr == nil {
2018-06-03 20:35:41 +02:00
firstErr = fmt . Errorf ( "dhcp6: %v" , err )
2018-06-14 18:28:40 +02:00
} else {
log . Printf ( "cannot apply dhcp6 lease: %v" , err )
2018-06-02 17:36:36 +02:00
}
2018-05-27 17:30:42 +02:00
}
2018-06-18 08:04:56 +02:00
for _ , process := range [ ] string {
2018-06-26 18:01:01 +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
2018-06-18 08:04:56 +02:00
} {
if err := notify . Process ( "/user/" + process , syscall . SIGUSR1 ) ; err != nil {
log . Printf ( "notifying %s: %v" , process , err )
}
2018-06-17 20:44:25 +02:00
}
2018-05-27 17:30:42 +02:00
if err := applySysctl ( ) ; err != nil {
2018-06-02 17:36:36 +02:00
if firstErr == nil {
2018-06-03 20:35:41 +02:00
firstErr = fmt . Errorf ( "sysctl: %v" , err )
2018-06-14 18:28:40 +02:00
} else {
log . Printf ( "cannot apply sysctl config: %v" , err )
2018-06-02 17:36:36 +02:00
}
2018-05-27 17:30:42 +02:00
}
2018-06-05 08:51:51 +02:00
if err := applyFirewall ( dir ) ; err != nil {
2018-06-03 20:35:41 +02:00
return fmt . Errorf ( "firewall: %v" , err )
2018-05-27 17:30:42 +02:00
}
2018-06-02 17:36:36 +02:00
return firstErr
2018-05-27 17:30:42 +02:00
}