krolaw / dhcp4 Goto Github PK
View Code? Open in Web Editor NEWDHCP4 library written in Go.
License: BSD 3-Clause "New" or "Revised" License
DHCP4 library written in Go.
License: BSD 3-Clause "New" or "Revised" License
In packet.go
line 260 & 261
This is typo?
It would be nice to have support for option 82 as described in RFC3046.
Also see http://blog.ine.com/2009/07/22/understanding-dhcp-option-82/
Hi.
There is a way to create a dhcp client with this library?
Seems like serverId variable has some random prefix which will show up when converting to []byte, then fill in the structure. https://github.com/krolaw/dhcp4/blob/master/packet.go#L179
Please take a look at this screen capture from Wireshark . IP is 127.0.0.1, which is 7f000001 and last 4 bytes.
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)
}
}
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
ListenAndServeIf("eth0", handler)
ListenAndServeIf("eth1", handler)
Error:
listen udp4 :67: bind: address already in use
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
?
I no longer work on projects requiring DHCP and am therefore not suited to maintain this library. Anyone interested it taking over?
Is it possible to set another DNS server?
dhcp.OptionDomainNameServer
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)
}
}()
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
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!
I propose that the project is released with a permissive license, such as the BSD License which is used by the Go project itself.
https://code.google.com/p/go/source/browse/LICENSE
This allows both proprietary and open source implementations to use code from the project.
Does not support next-server because siaddr not add to packet in ReplyPacket()
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.
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 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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.