summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMikael Magnusson <mikma@users.sourceforge.net>2020-03-10 22:56:17 +0100
committerMikael Magnusson <mikma@users.sourceforge.net>2020-03-17 20:06:04 +0100
commitb2d4ccf8ae00c077aa58b4c7af345752ae675149 (patch)
tree1a997f278458e771051db7e9c81bf48e1d1ded21
parent32896ab56d9ff767af9ed00cb5c9954edb0a2a81 (diff)
WIP DHCP FSM
-rw-r--r--pkg/tcpip/sample/wg_tunnel/fsm.go187
-rw-r--r--pkg/tcpip/sample/wg_tunnel/main.go129
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