diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | README.md | 198 | ||||
-rw-r--r-- | dhcpv6/server6/server.go | 46 | ||||
-rw-r--r-- | examples/client6/README.md | 5 | ||||
-rw-r--r-- | examples/client6/main.go | 42 | ||||
-rw-r--r-- | examples/packetcrafting6/README.md | 26 | ||||
-rw-r--r-- | examples/packetcrafting6/main.go | 72 | ||||
-rw-r--r-- | examples/server6/README.md | 10 | ||||
-rw-r--r-- | examples/server6/main.go | 27 | ||||
-rwxr-xr-x | examples/server6/server6 | bin | 0 -> 2842321 bytes |
10 files changed, 192 insertions, 237 deletions
@@ -1 +1,4 @@ .*.swp +examples/client6/client6 +examples/client4/client4 +examples/packetcrafting6/packetcrafting6 @@ -31,199 +31,15 @@ go get -u github.com/insomniacslk/dhcp/dhcpv{4,6} The sections below will illustrate how to use the `dhcpv6` and `dhcpv4` packages. -See more example code at https://github.com/insomniacslk/exdhcp - - -## DHCPv6 client - -To run a DHCPv6 transaction on the interface "eth0": - -```go -package main - -import ( - "log" - - "github.com/insomniacslk/dhcp/dhcpv6" -) - - -func main() { - // NewClient sets up a new DHCPv6 client with default values - // for read and write timeouts, for destination address and listening - // address - client := dhcpv6.NewClient() - - // 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 - // return a non-empty packet list even if there is an error. This is - // intended, because the transaction may fail at any point, and we - // still want to know what packets were exchanged until then. - // A default Solicit packet will be used during the "conversation", - // which can be manipulated by using modifiers. - conversation, err := client.Exchange("eth0") - - // Summary() prints a verbose representation of the exchanged packets. - for _, packet := range conversation { - log.Print(packet.Summary()) - } - // error handling is done *after* printing, so we still print the - // exchanged packets if any, as explained above. - if err != nil { - log.Fatal(err) - } -} -``` - - -## DHCPv6 packet crafting and manipulation - -```go -package main - -import ( - "log" - "net" - - "github.com/insomniacslk/dhcp/dhcpv6" - "github.com/insomniacslk/dhcp/iana" -) - -func main() { - // In this example we create and manipulate a DHCPv6 solicit packet - // and encapsulate it in a relay packet. To to this, we use - // `dhcpv6.DHCPv6Message` and `dhcpv6.DHCPv6Relay`, two structures - // that implement the `dhcpv6.DHCPv6` interface. - // Then print the wire-format representation of the packet. - - // Create the DHCPv6 Solicit first, using the interface "eth0" - // to get the MAC address - msg, err := dhcpv6.NewSolicitForInterface("eth0") - if err != nil { - log.Fatal(err) - } - - // In this example I want to redact the MAC address of my - // network interface, so instead of replacing it manually, - // I will show how to use modifiers for the purpose. - // A Modifier is simply a function that can be applied on - // a DHCPv6 object to manipulate it. Here we use it to - // replace the MAC address with a dummy one. - // Modifiers can be passed to many functions, for example - // to constructors, `Exchange()`, `Solicit()`, etc. Check - // the source code to know where to use them. - // Existing modifiers are implemented in dhcpv6/modifiers.go . - mac, err := net.ParseMAC("00:fa:ce:b0:0c:00") - if err != nil { - log.Fatal(err) - } - duid := dhcpv6.Duid{ - Type: dhcpv6.DUID_LLT, - HwType: iana.HwTypeEthernet, - Time: dhcpv6.GetTime(), - LinkLayerAddr: mac, - } - // As suggested above, an alternative is to call - // dhcpv6.NewSolicitForInterface("eth0", dhcpv6.WithCLientID(duid)) - msg = dhcpv6.WithClientID(duid)(msg) - - // Now encapsulate the message in a DHCPv6 relay. - // As per RFC3315, the link-address and peer-address have - // to be set by the relay agent. We use dummy values here. - linkAddr := net.ParseIP("2001:0db8::1") - peerAddr := net.ParseIP("2001:0db8::2") - relay, err := dhcpv6.EncapsulateRelay(msg, dhcpv6.MessageTypeRelayForward, linkAddr, peerAddr) - if err != nil { - log.Fatal(err) - } - - // Print a verbose representation of the relay packet, that will also - // show a short representation of the inner Solicit message. - // To print a detailed summary of the inner packet, extract it - // first from the relay using `relay.GetInnerMessage()`. - log.Print(relay.Summary()) - - // And finally, print the bytes that would be sent on the wire - log.Print(relay.ToBytes()) +* [dhcpv6 client](examples/client6/) +* [dhcpv6 server](examples/server6/) +* [dhcpv6 packet crafting](examples/packetcrafting6) +* TODO dhcpv4 client +* TODO dhcpv4 server +* TODO dhcpv4 packet crafting - // Note: there are many more functions in the library, check them - // out in the source code. For example, if you want to decode a - // byte stream into a DHCPv6 message or relay, you can use - // `dhcpv6.FromBytes`. -} -``` - -The output (slightly modified for readability) is -``` -$ go run main.go -2018/11/08 13:56:31 DHCPv6Relay - messageType=RELAY-FORW - hopcount=0 - linkaddr=2001:db8::1 - peeraddr=2001:db8::2 - options=[OptRelayMsg{relaymsg=DHCPv6Message(messageType=SOLICIT transactionID=0x9e0242, 4 options)}] - -2018/11/08 13:56:31 [12 0 32 1 13 184 0 0 0 0 0 0 0 0 0 0 0 1 32 1 13 184 - 0 0 0 0 0 0 0 0 0 0 0 2 0 9 0 52 1 158 2 66 0 1 0 14 - 0 1 0 1 35 118 253 15 0 250 206 176 12 0 0 6 0 4 0 23 - 0 24 0 8 0 2 0 0 0 3 0 12 250 206 176 12 0 0 14 16 0 - 0 21 24] -``` - -## DHCPv6 server - -A DHCPv6 server requires the user to implement a request handler. Basically the -user has to provide the logic to answer to each packet. The library offers a few -facilities to forge response packets, e.g. `NewAdvertiseFromSolicit`, -`NewReplyFromDHCPv6Message` and so on. Look at the source code to see what's -available. - -An example server that will print (but not reply to) the client's request is -shown below: - -```go -package main - -import ( - "log" - "net" - - "github.com/insomniacslk/dhcp/dhcpv6" -) - -func handler(conn net.PacketConn, peer net.Addr, m dhcpv6.DHCPv6) { - // this function will just print the received DHCPv6 message, without replying - log.Print(m.Summary()) -} -func main() { - laddr := net.UDPAddr{ - IP: net.ParseIP("::1"), - Port: dhcpv6.DefaultServerPort, - } - server := dhcpv6.NewServer(laddr, handler) - - defer server.Close() - if err := server.ActivateAndServe(); err != nil { - log.Panic(err) - } -} -``` - -## DHCPv4 client - -TODO - - -## DHCPv4 packet parsing - -TODO - - -## DHCPv4 server - -TODO +See more example code at https://github.com/insomniacslk/exdhcp # Public projects that use it diff --git a/dhcpv6/server6/server.go b/dhcpv6/server6/server.go index 5c84f97..6a6d0b7 100644 --- a/dhcpv6/server6/server.go +++ b/dhcpv6/server6/server.go @@ -10,52 +10,6 @@ import ( "github.com/insomniacslk/dhcp/dhcpv6" ) -/* - To use the DHCPv6 server code you have to call NewServer with two arguments: - - a handler function, that will be called every time a valid DHCPv6 packet is - received, and - - an address to listen on. - - The handler is a function that takes as input a packet connection, that can be - used to reply to the client; a peer address, that identifies the client sending - the request, and the DHCPv6 packet itself. Just implement your custom logic in - the handler. - - The address to listen on is used to know IP address, port and optionally the - scope to create and UDP6 socket to listen on for DHCPv6 traffic. - - Example program: - - -package main - -import ( - "log" - "net" - - "github.com/insomniacslk/dhcp/dhcpv6" -) - -func handler(conn net.PacketConn, peer net.Addr, m dhcpv6.DHCPv6) { - // this function will just print the received DHCPv6 message, without replying - log.Print(m.Summary()) -} - -func main() { - laddr := net.UDPAddr{ - IP: net.ParseIP("::1"), - Port: dhcpv6.DefaultServerPort, - } - server := dhcpv6.NewServer(laddr, handler) - - defer server.Close() - if err := server.ActivateAndServe(); err != nil { - log.Panic(err) - } -} - -*/ - // Handler is a type that defines the handler function to be called every time a // valid DHCPv6 message is received type Handler func(conn net.PacketConn, peer net.Addr, m dhcpv6.DHCPv6) diff --git a/examples/client6/README.md b/examples/client6/README.md new file mode 100644 index 0000000..5fa7bfa --- /dev/null +++ b/examples/client6/README.md @@ -0,0 +1,5 @@ +# DHCPv6 client + +A minimal DHCPv6 client can be implemented in a few lines of code, by using the default +client parameters. The example in [main.go](./main.go) lets you specify the +interface to send packets through, and defaults to `eth0`. diff --git a/examples/client6/main.go b/examples/client6/main.go new file mode 100644 index 0000000..41cf692 --- /dev/null +++ b/examples/client6/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "flag" + "log" + + "github.com/insomniacslk/dhcp/dhcpv6/client6" +) + +var ( + iface = flag.String("i", "eth0", "Interface to configure via DHCPv6") +) + +func main() { + flag.Parse() + log.Printf("Starting DHCPv6 client on interface %s", *iface) + + // NewClient sets up a new DHCPv6 client with default values + // for read and write timeouts, for destination address and listening + // address + client := client6.NewClient() + + // 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 + // return a non-empty packet list even if there is an error. This is + // intended, because the transaction may fail at any point, and we + // still want to know what packets were exchanged until then. + // A default Solicit packet will be used during the "conversation", + // which can be manipulated by using modifiers. + conversation, err := client.Exchange(*iface) + + // Summary() prints a verbose representation of the exchanged packets. + for _, packet := range conversation { + log.Print(packet.Summary()) + } + // error handling is done *after* printing, so we still print the + // exchanged packets if any, as explained above. + if err != nil { + log.Fatal(err) + } +} diff --git a/examples/packetcrafting6/README.md b/examples/packetcrafting6/README.md new file mode 100644 index 0000000..cf1a370 --- /dev/null +++ b/examples/packetcrafting6/README.md @@ -0,0 +1,26 @@ +# DHCPv6 packet crafting + +It is easy to parse, create and manipulate DHCPv6 packets. The `DHCPv6` +interface is the central way to move packets around. Two concrete +implementations, `DHCPv6Message` and `DHCPv6Relay` take care of the +details. The example in [main.go](./main.go) shows how to craft a DHCP6 +Solicit message with a custom DUID_LLT, encapsulate it in a Relay message, +and print its details. + + +The output (slightly modified for readability) is +``` +$ go run main.go +2018/11/08 13:56:31 DHCPv6Relay + messageType=RELAY-FORW + hopcount=0 + linkaddr=2001:db8::1 + peeraddr=2001:db8::2 + options=[OptRelayMsg{relaymsg=DHCPv6Message(messageType=SOLICIT transactionID=0x9e0242, 4 options)}] + +2018/11/08 13:56:31 [12 0 32 1 13 184 0 0 0 0 0 0 0 0 0 0 0 1 32 1 13 184 + 0 0 0 0 0 0 0 0 0 0 0 2 0 9 0 52 1 158 2 66 0 1 0 14 + 0 1 0 1 35 118 253 15 0 250 206 176 12 0 0 6 0 4 0 23 + 0 24 0 8 0 2 0 0 0 3 0 12 250 206 176 12 0 0 14 16 0 + 0 21 24] +``` diff --git a/examples/packetcrafting6/main.go b/examples/packetcrafting6/main.go new file mode 100644 index 0000000..afba3a0 --- /dev/null +++ b/examples/packetcrafting6/main.go @@ -0,0 +1,72 @@ +package main + +import ( + "log" + "net" + + "github.com/insomniacslk/dhcp/dhcpv6" + "github.com/insomniacslk/dhcp/iana" +) + +func main() { + // In this example we create and manipulate a DHCPv6 solicit packet + // and encapsulate it in a relay packet. To to this, we use + // `dhcpv6.DHCPv6Message` and `dhcpv6.DHCPv6Relay`, two structures + // that implement the `dhcpv6.DHCPv6` interface. + // Then print the wire-format representation of the packet. + + // Create the DHCPv6 Solicit first, using the interface "eth0" + // to get the MAC address + msg, err := dhcpv6.NewSolicitForInterface("eth0") + if err != nil { + log.Fatal(err) + } + + // In this example I want to redact the MAC address of my + // network interface, so instead of replacing it manually, + // I will show how to use modifiers for the purpose. + // A Modifier is simply a function that can be applied on + // a DHCPv6 object to manipulate it. Here we use it to + // replace the MAC address with a dummy one. + // Modifiers can be passed to many functions, for example + // to constructors, `Exchange()`, `Solicit()`, etc. Check + // the source code to know where to use them. + // Existing modifiers are implemented in dhcpv6/modifiers.go . + mac, err := net.ParseMAC("00:fa:ce:b0:0c:00") + if err != nil { + log.Fatal(err) + } + duid := dhcpv6.Duid{ + Type: dhcpv6.DUID_LLT, + HwType: iana.HWTypeEthernet, + Time: dhcpv6.GetTime(), + LinkLayerAddr: mac, + } + // As suggested above, an alternative is to call + // dhcpv6.NewSolicitForInterface("eth0", dhcpv6.WithCLientID(duid)) + msg = dhcpv6.WithClientID(duid)(msg) + + // Now encapsulate the message in a DHCPv6 relay. + // As per RFC3315, the link-address and peer-address have + // to be set by the relay agent. We use dummy values here. + linkAddr := net.ParseIP("2001:0db8::1") + peerAddr := net.ParseIP("2001:0db8::2") + relay, err := dhcpv6.EncapsulateRelay(msg, dhcpv6.MessageTypeRelayForward, linkAddr, peerAddr) + if err != nil { + log.Fatal(err) + } + + // Print a verbose representation of the relay packet, that will also + // show a short representation of the inner Solicit message. + // To print a detailed summary of the inner packet, extract it + // first from the relay using `relay.GetInnerMessage()`. + log.Print(relay.Summary()) + + // And finally, print the bytes that would be sent on the wire + log.Print(relay.ToBytes()) + + // Note: there are many more functions in the library, check them + // out in the source code. For example, if you want to decode a + // byte stream into a DHCPv6 message or relay, you can use + // `dhcpv6.FromBytes`. +} diff --git a/examples/server6/README.md b/examples/server6/README.md new file mode 100644 index 0000000..490fa72 --- /dev/null +++ b/examples/server6/README.md @@ -0,0 +1,10 @@ +# DHCPv6 server + +A DHCPv6 server requires the user to implement a request handler. Basically the +user has to provide the logic to answer to each packet. The library offers a few +facilities to forge response packets, e.g. `NewAdvertiseFromSolicit`, +`NewReplyFromDHCPv6Message` and so on. Look at the source code to see what's +available. + +An example server that will print (but not reply to) the client's request is +shown in [main.go](./main.go) diff --git a/examples/server6/main.go b/examples/server6/main.go new file mode 100644 index 0000000..174f798 --- /dev/null +++ b/examples/server6/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "log" + "net" + + "github.com/insomniacslk/dhcp/dhcpv6" + "github.com/insomniacslk/dhcp/dhcpv6/server6" +) + +func handler(conn net.PacketConn, peer net.Addr, m dhcpv6.DHCPv6) { + // this function will just print the received DHCPv6 message, without replying + log.Print(m.Summary()) +} + +func main() { + laddr := net.UDPAddr{ + IP: net.ParseIP("::1"), + Port: dhcpv6.DefaultServerPort, + } + server := server6.NewServer(laddr, handler) + + defer server.Close() + if err := server.ActivateAndServe(); err != nil { + log.Panic(err) + } +} diff --git a/examples/server6/server6 b/examples/server6/server6 Binary files differnew file mode 100755 index 0000000..16f6153 --- /dev/null +++ b/examples/server6/server6 |