summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--README.md198
-rw-r--r--dhcpv6/server6/server.go46
-rw-r--r--examples/client6/README.md5
-rw-r--r--examples/client6/main.go42
-rw-r--r--examples/packetcrafting6/README.md26
-rw-r--r--examples/packetcrafting6/main.go72
-rw-r--r--examples/server6/README.md10
-rw-r--r--examples/server6/main.go27
-rwxr-xr-xexamples/server6/server6bin0 -> 2842321 bytes
10 files changed, 192 insertions, 237 deletions
diff --git a/.gitignore b/.gitignore
index a01ee28..432360e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
.*.swp
+examples/client6/client6
+examples/client4/client4
+examples/packetcrafting6/packetcrafting6
diff --git a/README.md b/README.md
index 6a2095e..9320677 100644
--- a/README.md
+++ b/README.md
@@ -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
new file mode 100755
index 0000000..16f6153
--- /dev/null
+++ b/examples/server6/server6
Binary files differ