Git Product home page Git Product logo

dhcp4's Introduction

DHCP4 - A DHCP library written in Go.

Original Author

http://richard.warburton.it/

Quick Start

See example_test.go for how to use this library to create a basic server.

Documentation

http://godoc.org/github.com/krolaw/dhcp4

Thanks

Special thanks to:

Wow

DHCP4 was one of the libraries used by Facebook's DHCP load balancing relay. "Facebook currently uses it in production, and it's deployed at global scale across all of our data centers." FB has since moved to another lib.

dhcp4's People

Contributors

baptr avatar bgpat avatar cdevr avatar deanrock avatar edwardbetts avatar emmaly avatar isantospardo avatar krolaw avatar mdlayher avatar michaelharo avatar mrdg avatar tfheen avatar vincentbernat avatar zirokyl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dhcp4's Issues

Packet data is broken on DHCP OFFER

I have a small embedded DHCP server based on your example. While it works fine with dhclient - it fails on systemd-networkd, e.g - the lease can't be obtained. After some tinkering/debugging I realized that the server ID is not set properly. Systemd reports:

DHCP CLIENT (0xfb50f277): DISCOVER
Failed to parse server identifier, ignoring: Invalid argument
DHCP CLIENT (0xfb50f277): received lease lacks address, server address or lease lifetime, ignoring

I was able to isolate the test case with the sample request/response ( also on playground https://play.golang.org/p/54GThoEJZ9K )

It looks like the option bounds are not set properly in the response.

=== RUN   TestOptionValues
[255 255 255 0]
[10 11 12 13]
--- PASS: TestOptionValues (0.00s)
=== RUN   TestOutgoingPacketParsing
--- FAIL: TestOutgoingPacketParsing (0.00s)
    dhcpsrv_test.go:60: Expected server IP [10 101 1 1], actual IP [0 0 0 0 0 0 0 0 0 0 255 255 10 101 1 1]

package main

import (
	"fmt"
	"net"
	"reflect"
	"testing"
	"time"

	dhcp "github.com/krolaw/dhcp4"
)

var (
	incomingData = []byte{1, 1, 6, 0, 244, 101, 245, 221, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 111, 115, 116, 80, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 130, 83, 99, 53, 1, 1, 61, 19, 255, 254, 220, 71, 216, 0, 2, 0, 0, 171, 17, 138, 52, 26, 55, 116, 247, 151, 249, 55, 8, 1, 3, 12, 15, 6, 33, 121, 42, 57, 2, 2, 64, 12, 6, 100, 101, 118, 98, 111, 120, 255}
	outgoingData = []byte{2, 1, 6, 0, 244, 101, 245, 221, 0, 0, 0, 0, 0, 0, 0, 0, 10, 101, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 72, 111, 115, 116, 80, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 130, 83, 99, 53, 1, 2, 54, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 10, 101, 1, 1, 51, 4, 0, 0, 28, 32, 1, 4, 255, 255, 255, 0, 255}
)

func TestOptionValues(t *testing.T) {
	test := []struct {
		opt      dhcp.OptionCode
		expected []byte
	}{
		{
			opt:      dhcp.OptionSubnetMask,
			expected: []byte{255, 255, 255, 0},
		},
		{
			opt:      dhcp.OptionServerIdentifier,
			expected: []byte{10, 11, 12, 13},
		},
	}
	p := dhcp.NewPacket(2)
	for _, opt := range test {
		p.AddOption(opt.opt, opt.expected)
	}
	p.PadToMinSize()
	newOpts := p.ParseOptions()
	for _, opt := range test {
		if target := newOpts[opt.opt]; !reflect.DeepEqual(target, opt.expected) {
			t.Fatalf("Option %d mismatch: expected %+v, actual %+v", opt.opt, opt.expected, target)
		} else {
			fmt.Printf("%+v\n", target)
		}
	}
}

func TestOutgoingPacketParsing(t *testing.T) {
	p := dhcp.Packet(incomingData)
	expected := []byte{10, 101, 1, 1}
	rteOpts := dhcp.Options{
		dhcp.OptionSubnetMask: []byte{255, 255, 255, 0},
	}
	opts := rteOpts.SelectOrderOrAll(p.ParseOptions()[dhcp.OptionParameterRequestList])
	newP := dhcp.ReplyPacket(p, dhcp.Offer, net.IPv4(10, 101, 1, 1), net.IPv4(10, 101, 1, 2), 2*time.Hour, opts)
	if !reflect.DeepEqual([]byte(newP), outgoingData) {
		t.Fatalf("Packet data mismatch: \n%+v\n%+v\n", newP, outgoingData)
	}
	serverID := newP.ParseOptions()[dhcp.OptionServerIdentifier]
	if !reflect.DeepEqual(serverID, expected) {
		t.Fatalf("Expected server IP %+v, actual IP %+v", expected, serverID)
	}
}

Looking for new Maintainer

I no longer work on projects requiring DHCP and am therefore not suited to maintain this library. Anyone interested it taking over?

How to determine interface from within handler?

I'm using the ListenAndServe method to register my handler, so the same handler will be used for responding for all interfaces. How do I determine (from within the handler) which interface a DHCP packet was received on? I looked at the documentation and this information does not seems to be exposed.

why bad udp cksum 0x95d2 -> 0x9062!

I use the file "github.com/krolaw/dhcp4/example_test.go" without any change (dhcp-server is deployed on 10.226.137.197) ,but I found the result as follows

tcpdump -i eth0 -vvv -s 1500 port 67 -env

s [none], proto UDP (17), length 328)
0.0.0.0.bootpc > 255.255.255.255.bootps: [udp sum ok] BOOTP/DHCP, Request from 00:50:56:bb:4f:cf, length 300, xid 0xb73d675d, Flags [none] (0x0000)
Client-Ethernet-Address 00:50:56:bb:4f:cf
Vendor-rfc1048 Extensions
Magic Cookie 0x63825363
DHCP-Message Option 53, length 1: Request
Server-ID Option 54, length 4: 10.226.137.197
Requested-IP Option 50, length 4: 10.226.137.201
Hostname Option 12, length 13: "1-1-1-204-TOR"
Parameter-Request Option 55, length 18:
Subnet-Mask, BR, Time-Zone, Classless-Static-Route
Domain-Name, Domain-Name-Server, Hostname, YD
YS, NTP, MTU, Option 119
Default-Gateway, Classless-Static-Route, Classless-Static-Route-Microsoft, Static-Route
Option 252, NTP
END Option 255, length 0
PAD Option 0, length 0, occurs 9
16:04:18.085091 04:b0:e7:95:44:9b > Broadcast, ethertype IPv4 (0x0800), length 316: (tos 0x0, ttl 64, id 50934, offset 0, flags [DF], proto UDP (17), length 302)
10.226.137.197.bootps > 255.255.255.255.bootpc: [bad udp cksum 0x95d2 -> 0x9062!] BOOTP/DHCP, Reply, length 274, xid 0xb73d675d, Flags [none] (0x0000)
Your-IP 10.226.137.201
Client-Ethernet-Address 00:50:56:bb:4f:cf
Vendor-rfc1048 Extensions
Magic Cookie 0x63825363
DHCP-Message Option 53, length 1: ACK
Server-ID Option 54, length 4: 10.226.137.197
Lease-Time Option 51, length 4: 120
Subnet-Mask Option 1, length 4: 255.255.240.0
Domain-Name-Server Option 6, length 4: 10.226.137.197
Default-Gateway Option 3, length 4: 10.226.137.197
END Option 255, length 0

Reply not sent to DHCP Relay when Broadcast flag set

We use parts of this library with a custom handler implementation for:
https://github.com/digitalrebar/provision

We did this before some of your more recent changes to interface binding. We may re-evaluate that later to see if we can switch back out of the custom interface code we use.

Regardless, we encountered in the field an issue that appears in the current code base. A DHCP client sets the Broadcast flag bit in a request, but a DHCP relay is used to forward the packet to our server. In this case, the reply code will generate a broadcast message instead of sending back to the giaddr field as per the spec.

The issue is around line 70 in server.go. To address the issue, we do this:

                    port, _ := strconv.Atoi(portStr)
                    if req.GIAddr().Equal(net.IPv4zero) {
                            if net.ParseIP(ipStr).Equal(net.IPv4zero) || req.Broadcast() {
                                    addr = &net.UDPAddr{IP: net.IPv4bcast, Port: port}
                            }
                    } else {
                            addr = &net.UDPAddr{IP: req.GIAddr(), Port: port}
                    }

Hope this helps. Thanks for your work.

I suggest to migrate from deprecated syscall package to golang.org/x/sys/unix package

I think that syscall Golang package is deprecated:

NOTE: This package is locked down. Code outside the standard Go repository should be migrated to use the corresponding package in the golang.org/x/sys repository. That is also where updates required by new systems or versions should be applied. Signal, Errno and SysProcAttr are not yet available in golang.org/x/sys and must still be referenced from the syscall package. See https://golang.org/s/go1.4-syscall for more information.

I think dhcp4 lib need to migrate to https://godoc.org/golang.org/x/sys/unix

PadToMinSize may break AddOption

AddOption expects that the packet is ended with END, but if the initial packet was smaller than 300 bytes, PadToMinSize is called and so the packet is padded and AddOption doesn't remove the END.

Can we postpone PadToMinSize until Serve?

Use the server without a physical interface

Hi All,
has anyone tried to send packets coming from a gRPC connection to the DHCP Server?

I believe it should be enough to create a custom ServeConn that listen on a channel and forwards the packet, but I couldn't find any example on how to do that. Does someone has experience with that?

Thanks in advance

Teo

dhcp client

Hi.
There is a way to create a dhcp client with this library?

OptionBootFileName example

Hi is it possible to write an example for the usage of OptionBootFileName? I just added

dhcp.OptionBootFileName:     []byte("/pxelinux.0")

to the options but that wont work (the client gets "No filename").

Thx!

how to stop dhcp server?

I'm using this library in my project on linux and I need to run server within goroutine and stop it after, so how can I do this?
here is a sample of my code, also I'm trying to setup server on a virtual interface here

pc, _ := conn.NewUDP4BoundListener(ifName, ":67")
go func() {
  if err := dhcp4.Serve(pc, handler); err != nil {
	  panic(err)
  }

}()

next-server

Does not support next-server because siaddr not add to packet in ReplyPacket()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.