diff options
author | Mikael Magnusson <mikma@users.sourceforge.net> | 2020-03-10 22:56:17 +0100 |
---|---|---|
committer | Mikael Magnusson <mikma@users.sourceforge.net> | 2020-03-17 20:06:04 +0100 |
commit | b2d4ccf8ae00c077aa58b4c7af345752ae675149 (patch) | |
tree | 1a997f278458e771051db7e9c81bf48e1d1ded21 | |
parent | 32896ab56d9ff767af9ed00cb5c9954edb0a2a81 (diff) |
WIP DHCP FSM
-rw-r--r-- | pkg/tcpip/sample/wg_tunnel/fsm.go | 187 | ||||
-rw-r--r-- | pkg/tcpip/sample/wg_tunnel/main.go | 129 |
2 files changed, 264 insertions, 52 deletions
diff --git a/pkg/tcpip/sample/wg_tunnel/fsm.go b/pkg/tcpip/sample/wg_tunnel/fsm.go new file mode 100644 index 000000000..965f6fca9 --- /dev/null +++ b/pkg/tcpip/sample/wg_tunnel/fsm.go @@ -0,0 +1,187 @@ +package main + +import ( + "fmt" +// "log" + "github.com/insomniacslk/dhcp/dhcpv6" +) + +// FSM from RFC 2131 Figure 5 + +type DHCP interface { + SendDiscover() + SendRequest() +} + +type FSM struct { + state State + dhcp DHCP +} + +type DHCPv4 struct { +} + +func (f FSM) Init(d DHCP) { + fmt.Println("Init") + f.dhcp = d + f.state = stInit(f.dhcp, nil) + + // go +} + +func (f FSM) InputMessage() { +} + +func (d DHCPv4) SendDiscover() { +} + +type DHCPv6 struct { +} + +func (d DHCPv6) SendDiscover() { + fmt.Println("SendDiscover") +} + +func (d DHCPv6) SendRequest() { + fmt.Println("SendRequest") +} + +type EventType uint8 + +const ( + EventTypeNone EventType = 0 + EventTypeMessage EventType = 1 + EventTypeTimeoutT1 EventType = 2 + EventTypeTimeoutT2 EventType = 3 + EventTypeTimeoutLease EventType = 3 +) + +type Event interface { + Type() EventType +} + +// type TimerType uint8 + +// const ( +// TimerNone TimerType = 0 +// TimerT1 TimerType = 1 +// TimerT2 TimerType = 2 +// TimerLease TimerType = 3 +// ) + +// type EventTimeout struct { +// Event +// Timer TimerType +// } + +type EventMessage struct { + Event + msg dhcpv6.Message +} + +func (ev *EventMessage) Type() EventType { + return EventTypeMessage +} + +func (ev *EventMessage) Msg() dhcpv6.Message { + return ev.msg +} + +type State func (d DHCP, ev Event) (next State) + +func stInit(d DHCP, ev Event) State { + // Send Discover + d.SendDiscover() + return stSelecting +} + +func stSelecting(d DHCP, ev Event) State { + switch ev.Type() { + case EventTypeMessage: + msg := ev.(*EventMessage).Msg() + switch msg.Type() { + case dhcpv6.MessageTypeAdvertise: + // Select first offer + d.SendRequest() + return stRequesting + } + } + return stSelecting +} + +func stRequesting(d DHCP, ev Event) State { + switch ev.Type() { + case EventTypeMessage: + msg := ev.(*EventMessage).Msg() + switch msg.Type() { + case dhcpv6.MessageTypeAdvertise: + // Discard + return stRequesting + case dhcpv6.MessageTypeReply: + // Record lease, set T1, T2 + return stBound + case dhcpv6.MessageTypeNone: // FIXME NAK + // Send Decline + return stInit + } + } + return stRequesting +} + +func stBound(d DHCP, ev Event) State { + switch ev.Type() { + case EventTypeTimeoutT1: + // Send Request + return stRenewing + case EventTypeMessage: + msg := ev.(*EventMessage).Msg() + switch msg.Type() { + case dhcpv6.MessageTypeAdvertise: + case dhcpv6.MessageTypeReply: + case dhcpv6.MessageTypeNone: + // TODO or NACK + // Send Decline + return stBound + } + } + return stBound +} + +func stRenewing(d DHCP, ev Event) State { + // FIXME + switch ev.Type() { + case EventTypeTimeoutT2: + // Broadcast request? + return stRebinding + case EventTypeMessage: + msg := ev.(*EventMessage).Msg() + switch msg.Type() { + case dhcpv6.MessageTypeReply: + // Record lease, set T1, T2 + return stBound + case dhcpv6.MessageTypeNone: // FIXME NAK + // HALT network + return stInit + } + } + return stRenewing +} + +func stRebinding(d DHCP, ev Event) State { + switch ev.Type() { + case EventTypeTimeoutLease: + // Halt network + return stInit + case EventTypeMessage: + msg := ev.(*EventMessage).Msg() + switch msg.Type() { + case dhcpv6.MessageTypeReply: + // Record lease, set timers T1, T2 + return stBound + case dhcpv6.MessageTypeNone: // FIXME NAK + // Halt network + return stInit + } + } + return stRebinding +} diff --git a/pkg/tcpip/sample/wg_tunnel/main.go b/pkg/tcpip/sample/wg_tunnel/main.go index e11eee227..b859dff7a 100644 --- a/pkg/tcpip/sample/wg_tunnel/main.go +++ b/pkg/tcpip/sample/wg_tunnel/main.go @@ -48,7 +48,7 @@ import ( "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" "gvisor.dev/gvisor/pkg/tcpip/network/ipv6" "gvisor.dev/gvisor/pkg/tcpip/stack" - "gvisor.dev/gvisor/pkg/tcpip/transport/icmp" +// "gvisor.dev/gvisor/pkg/tcpip/transport/icmp" "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" "gvisor.dev/gvisor/pkg/tcpip/transport/udp" "gvisor.dev/gvisor/pkg/waiter" @@ -701,15 +701,17 @@ func withDHCPv4Msg(msg *dhcpv4.DHCPv4) dhcpv6.Modifier { } } -func NewDHCPv4Query(modifiers ...dhcpv6.Modifier) (*dhcpv6.Message, error) { +func NewDHCPv4Query(flags uint32, modifiers ...dhcpv6.Modifier) (*dhcpv6.Message, error) { msg, err := dhcpv6.NewMessage() if err != nil { return nil, err } //msg.MessageType = dhcpv6.MessageTypeDHCPv4Query FIXME msg.MessageType = 20 - msg.AddOption(&dhcpv6.OptElapsedTime{}) - //modifier = append([]dhcpv6.Modifier{WithRequestedOptions()}, modifier...} + msg.TransactionID = dhcpv6.TransactionID{byte(flags >> 16), byte(flags >> 8), byte(flags)} + //msg.AddOption(dhcpv6.OptElapsedTime(0)) + //modifiers = append([]dhcpv6.Modifier{dhcpv6.WithRequestedOptions(dhcpv6.OptionDHCP4oDHCP6Server)}, modifiers...) + for _, mod := range modifiers { mod(msg) } @@ -720,32 +722,48 @@ func (routes *Routes) doClient(s *stack.Stack, nic tcpip.NICID) { fmt.Println("doClient start") // TODO use link local address + fsm := FSM{} + fsm.Init(DHCPv6{}) + time.Sleep(500 * time.Millisecond) +// log.Fatal("FSM") +// state = state(dhcp, nil) - src := tcpip.Address(net.ParseIP("2001:470:dfae:6300::1:111").To16()) - dst := tcpip.Address(net.ParseIP("2001:470:dfae:6300::3").To16()) + //src := tcpip.Address(net.ParseIP("2001:470:dfae:6300::1:111").To16()) + //dst := tcpip.Address(net.ParseIP("2001:470:dfae:6300::3").To16()) + srcIp := net.ParseIP("fe80::111") + srcAddr := tcpip.Address(srcIp.To16()) + //srcUdp := net.UDPAddr{IP: srcIp, Port: 546} + src := tcpip.FullAddress{NIC: nic, Addr: srcAddr, Port: 546} + //dstIp := net.ParseIP("fe80::3") + //dstUdp := net.UDPAddr{IP: dstIp, Port: 547} + //dstAddr := tcpip.Address(dstIp.To16()) + //dst := tcpip.FullAddress{NIC: nic, Addr: dstAddr, Port: 547} conn, err := gonet.DialUDP(s, - &tcpip.FullAddress{NIC: nic, Addr: src, Port: 546}, - &tcpip.FullAddress{NIC: nic, Addr: dst, Port: 547}, - ipv6.ProtocolNumber) - if err != nil { + &src, + //&dst, + nil, + ipv6.ProtocolNumber); if err != nil { log.Fatal(err) } hwaddr := []byte("ABCDEF") - client, err := nclient6.NewWithConn(conn, hwaddr, nclient6.WithDebugLogger()) - if err != nil { + client, err := nclient6.NewWithConn(conn, hwaddr, nclient6.WithDebugLogger()); if err != nil { log.Fatal(err) } + //nclient6.WithBroadcastAddr(&dstUdp)(client) + duid := dhcpv6.Duid{ Type: dhcpv6.DUID_LL, HwType: iana.HWTypeEthernet, LinkLayerAddr: hwaddr, } - fqdnOpt := dhcpv6.WithFQDN(0x1, "gvisor.m7n.se") + hostName := "gvisor" + fqdn := hostName + ".m7n.se" + fqdnOpt := dhcpv6.WithFQDN(0x1, fqdn) iaPrefix := dhcpv6.OptIAPrefix{} iaPrefix.Prefix.Mask = net.CIDRMask(64, 128-64) @@ -764,49 +782,56 @@ func (routes *Routes) doClient(s *stack.Stack, nic tcpip.NICID) { dhcpv6.WithClientID(duid), dhcpv6.WithRequestedOptions(dhcpv6.OptionDHCP4oDHCP6Server), withDHCP4oDHCP6Server(net.ParseIP("fe80::1"), - net.ParseIP("fe80::2"))) - if err != nil { + net.ParseIP("fe80::2"))); if err != nil { log.Fatal(err) } + // Unicast require OPTION_UNICAST from server + //nclient6.WithBroadcastAddr(&dstUdp)(client) + //withIAPDFromAdvertise(adv) - msg, err := client.Request(context.Background(), adv, fqdnOpt) - if err != nil { + msg, err := client.Request(context.Background(), adv, fqdnOpt); if err != nil { log.Fatal(err) } - disc, err := dhcpv4.NewDiscovery(hwaddr, dhcpv4.WithOption(clientIDOpt)) - if err != nil { + modHostName := dhcpv4.WithGeneric(dhcpv4.OptionHostName, []byte(hostName)) + disc, err := dhcpv4.NewDiscovery(hwaddr, dhcpv4.WithOption(clientIDOpt), modHostName); if err != nil { log.Fatal(err) } - disc_query, err := NewDHCPv4Query(withDHCPv4Msg(disc)) - if err != nil { + disc_query, err := NewDHCPv4Query(0x800000, withDHCPv4Msg(disc)); if err != nil { log.Fatal(err) } serverAddr := nclient6.AllDHCPRelayAgentsAndServers - disc_resp, err := client.SendAndRead(context.Background(), serverAddr, disc_query, nil) - if err != nil { + disc_resp, err := client.SendAndRead(context.Background(), serverAddr, disc_query, nil); if err != nil { log.Fatal(err) } - offer := disc_resp.GetOneOption(dhcpv6.OptionDHCPv4Msg).(*dhcpv6.OptDHCPv4Msg).Msg - req, err := dhcpv4.NewRequestFromOffer(offer) - if err != nil { + msgOpt := disc_resp.GetOneOption(dhcpv6.OptionDHCPv4Msg); if msgOpt == nil { + log.Fatal("Missing DHCPv4Msg option in discovery") + } + + offer := msgOpt.(*dhcpv6.OptDHCPv4Msg).Msg + req, err := dhcpv4.NewRequestFromOffer(offer, modHostName); if err != nil { log.Fatal(err) } - req_query, err := NewDHCPv4Query(withDHCPv4Msg(req)) - if err != nil { + req_query, err := NewDHCPv4Query(0x800000, withDHCPv4Msg(req)); if err != nil { log.Fatal(err) } - ack, err := client.SendAndRead(context.Background(), serverAddr, req_query, nil) - if err != nil { + req_resp, err := client.SendAndRead(context.Background(), serverAddr, req_query, nil); if err != nil { log.Fatal(err) } + msgOpt = req_resp.GetOneOption(dhcpv6.OptionDHCPv4Msg); if msgOpt == nil { + log.Fatal("Missing DHCPv4Msg option in ack") + } + ack := msgOpt.(*dhcpv6.OptDHCPv4Msg).Msg + // client.Close() - fmt.Println("doClient end", ack) + fmt.Println("doClient end", ack.YourIPAddr, ack.SubnetMask()) + ip := net.IPNet{IP: ack.YourIPAddr, Mask:ack.SubnetMask()} + routes.addAddress(s, nic, ip.String()) iana := msg.GetOneOption(dhcpv6.OptionIANA).(*dhcpv6.OptIANA) for _, addr := range iana.Options.Get(dhcpv6.OptionIAAddr) { @@ -833,27 +858,27 @@ func (routes *Routes) doClient(s *stack.Stack, nic tcpip.NICID) { dumpAddresses(s) dumpRoutes(s) - if false { - // FIXME can't send non icmpv6 echo request - var wq waiter.Queue - ep, e := s.NewEndpoint(icmp.ProtocolNumber6, ipv6.ProtocolNumber, &wq) - if err != nil { - log.Fatal("NewEndpoint", e) - } - - v := []byte{0, 1, 2, 3} - raSrc := tcpip.FullAddress{NIC: nic, Addr: src, Port: 0} - raDst := tcpip.FullAddress{NIC: nic, Addr: dst, Port: 0} - if err := ep.Bind(raSrc); err != nil { - log.Fatal("Bind failed: ", err) - } - fmt.Println("Before write", raSrc.NIC, raSrc.Addr, raSrc.Port, raDst.NIC, raDst.Addr, raDst.Port) - ep.Write(tcpip.SlicePayload(v), - tcpip.WriteOptions{To:&raDst}) - - defer ep.Close() - fmt.Println("After write") - } + // if false { + // // FIXME can't send non icmpv6 echo request + // var wq waiter.Queue + // ep, e := s.NewEndpoint(icmp.ProtocolNumber6, ipv6.ProtocolNumber, &wq) + // if err != nil { + // log.Fatal("NewEndpoint", e) + // } + + // v := []byte{0, 1, 2, 3} + // raSrc := tcpip.FullAddress{NIC: nic, Addr: src, Port: 0} + // raDst := tcpip.FullAddress{NIC: nic, Addr: dst, Port: 0} + // if err := ep.Bind(raSrc); err != nil { + // log.Fatal("Bind failed: ", err) + // } + // fmt.Println("Before write", raSrc.NIC, raSrc.Addr, raSrc.Port, raDst.NIC, raDst.Addr, raDst.Port) + // ep.Write(tcpip.SlicePayload(v), + // tcpip.WriteOptions{To:&raDst}) + + // defer ep.Close() + // fmt.Println("After write") + // } // Exchange runs a Solicit-Advertise-Request-Reply transaction on the // specified network interface, and returns a list of DHCPv6 packets // (a "conversation") and an error if any. Notice that Exchange may |