Giter Club home page Giter Club logo

coredhcp's Introduction

coredhcp

Build Status codecov Go Report Card

Fast, multithreaded, modular and extensible DHCP server written in Go

This is still a work-in-progress

Example configuration

In CoreDHCP almost everything is implemented as a plugin. The order of plugins in the configuration matters: every request is evaluated calling each plugin in order, until one breaks the evaluation and responds to, or drops, the request.

The following configuration runs a DHCPv6-only server, listening on all the interfaces, using a custom server ID and DNS, and reading the leases from a text file.

server6:
    # this server will listen on all the available interfaces, on the default
    # DHCPv6 server port, and will join the default multicast groups. For more
    # control, see the `listen` directive in cmds/coredhcp/config.yml.example .
    plugins:
        - server_id: LL 00:de:ad:be:ef:00
        - file: "leases.txt"
        - dns: 8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844

For more complex examples, like how to listen on specific interfaces and configure other plugins, see config.yml.example.

Build and run

An example server is located under cmds/coredhcp/, so enter that directory first. To build a server with a custom set of plugins, see the "Server with custom plugins" section below.

Once you have a working configuration in config.yml (see config.yml.example), you can build and run the server:

$ cd cmds/coredhcp
$ go build
$ sudo ./coredhcp
INFO[2019-01-05T22:28:07Z] Registering plugin "file"
INFO[2019-01-05T22:28:07Z] Registering plugin "server_id"
INFO[2019-01-05T22:28:07Z] Loading configuration
INFO[2019-01-05T22:28:07Z] Found plugin: `server_id` with 2 args, `[LL 00:de:ad:be:ef:00]`
INFO[2019-01-05T22:28:07Z] Found plugin: `file` with 1 args, `[leases.txt]`
INFO[2019-01-05T22:28:07Z] Loading plugins...
INFO[2019-01-05T22:28:07Z] Loading plugin `server_id`
INFO[2019-01-05T22:28:07Z] plugins/server_id: loading `server_id` plugin
INFO[2019-01-05T22:28:07Z] plugins/server_id: using ll 00:de:ad:be:ef:00
INFO[2019-01-05T22:28:07Z] Loading plugin `file`
INFO[2019-01-05T22:28:07Z] plugins/file: reading leases from leases.txt
INFO[2019-01-05T22:28:07Z] plugins/file: loaded 1 leases from leases.txt
INFO[2019-01-05T22:28:07Z] Starting DHCPv6 listener on [::]:547
INFO[2019-01-05T22:28:07Z] Waiting
2019/01/05 22:28:07 Server listening on [::]:547
2019/01/05 22:28:07 Ready to handle requests
...

Then try it with the local test client, that is located under cmds/client/:

$ cd cmds/client
$ go build
$ sudo ./client
INFO[2019-01-05T22:29:21Z] &{ReadTimeout:3s WriteTimeout:3s LocalAddr:[::1]:546 RemoteAddr:[::1]:547}
INFO[2019-01-05T22:29:21Z] DHCPv6Message
  messageType=SOLICIT
  transactionid=0x6d30ff
  options=[
    OptClientId{cid=DUID{type=DUID-LLT hwtype=Ethernet hwaddr=00:11:22:33:44:55}}
    OptRequestedOption{options=[DNS Recursive Name Server, Domain Search List]}
    OptElapsedTime{elapsedtime=0}
    OptIANA{IAID=[250 206 176 12], t1=3600, t2=5400, options=[]}
  ]
...

Plugins

CoreDHCP is heavily based on plugins: even the core functionalities are implemented as plugins. Therefore, knowing how to write one is the key to add new features to CoreDHCP.

Core plugins can be found under the plugins directory. Additional plugins can also be found in the coredhcp/plugins repository.

Server with custom plugins

To build a server with a custom set of plugins you can use the coredhcp-generator tool. Head there for documentation on how to use it.

How to write a plugin

The best way to learn is to read the comments and source code of the example plugin, which guides you through the implementation of a simple plugin that prints a packet every time it is received by the server.

Authors

coredhcp's People

Contributors

adphi avatar borna-blazevic avatar bradbeam avatar candlerb avatar dependabot[bot] avatar dlad avatar dza1 avatar elmarco avatar hugelgupf avatar insomniacslk avatar intlabs avatar karnauskas avatar kworm83 avatar natolumin avatar pmazzini avatar skoef avatar stephen-fox avatar stickler-ci avatar toshic avatar wkronmiller 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

coredhcp's Issues

Lease storage API

Following #110 and #108 (comment) I want to start a discussion about what the lease storage API would/should look like. This is pretty long but I have no real conclusion at the end, I hope we can build feedback and some PoCs to see where we should go

Quick note about terminology:

  • consumer plugin: Uses the interface to query/store leases
  • provider plugin: Implements the interface, stores and maintains lease information

Basics

The base interface should act like a map, indexed by a client ID, returning leases

What's a client ID ?

Probably not the same for v4 and v6.
v4 usually identifies client by hardware address, but there's also a client-identifier option (61) that probably almost nobody actually uses
v6 client-ID option is mandatory and is probably much safer to use
However even in v6 administrators often care more about the MAC addresses. Which the RFC forbids but that ship has sailed

What's a lease ?

There's an expiration date. That's easy (not)(We'll come back to this later)
There's an IP. Or multiple (v6, multiple IA_ADDR in a single IA_NA). Or a prefix (or multiple)
There can be multiple leases per client. This is extremely common in v6 but not nearly as much in v4

Can we need to search/index by other than a client ID ?

For things like ad-hoc replication, or leasequery, we may need a bulk read(/write) interface

Do we need additional data in addition ?

  • Information on the validity on the lease ? Eg if there is relay info, a
    lease could be linked to a network segment, and if the client moves the
    lease becomes invalid.
    It might not need to be stored in the lease though

  • A solution could be to have optional auxiliary interface{} data. However
    this makes it harder to share a lease storage across several plugins (is
    that something we want? need?). Maybe index the additional data by
    plugin name/instance, and plugins can only retrieve leases they stored
    themselves

Usage (and locking)

The most common operation of a consumer plugin is a read-modify-update loop on a single client:

  • Receive the client request, fetch leases for the client
  • Extend and/or allocate one or more leases for the client
  • Write back the lease(s) to the provider

This means we need to prevent another plugin (or the same plugin in another
request) from modifying leases for a client we've "looked up" and intend to update.

Interface

Looking up a client gives, along with the info, a token (opaque, managed by the plugin), which has to be given during updates to ensure consistency of the results.
On the backend this can map nicely to multiple constructs:

  • For a key-value backend like eg consul, the token can be a modification
    index, which is atomically compared when updating the value, and the
    modification rejected if the base isn't the expected one
  • For an SQL backend this maps to a SELECT ... FOR UPDATE (or equivalent),
    where the backend opens a transaction, and the token can be an
    identifier/index to find the transaction later to complete it
  • For a simpler "in-memory map" backend it could also be ignored by the
    provider plugin and have Lookup/Update take a lock and block instead
type Token struct{
	pluginRef *plugins.Plugin // or just an index or something
	token     interface{}
}

type LeaseStorage interface {
	Lookup(clientID) (Token, []Lease, error)
	Update(clientID, Token, []Lease) error

	ReleaseToken(Token) // This is only necessary if Update is never called
}

Notice that some of these operations, instead of actually "locking", return
an error on races at the time of the update.

Errors and retrying

Due to the diversity of backends, there are many cases where some calls can
fail in retryable ways. We'll need to define, along with the interface, error
types that have to be handled in a specific way by the clients.
We can define the base errors and providers will wrap them, and clients test with the go 1.13 error API if they match (errors.Is)

At least:

  • A "Transport" related error (network issues, etc): Doesn't invalidate the
    token, retryable
  • A "Concurrency" related error: Invalidates the token, retryable (but needs a new lookup)

(This doesn't preclude other errors, eg for bad parameters)

Lease Expiration

Leases expire, and something needs to clean them up at some point.

Either the lease storage plugin or the calling plugin has to clean up expired
leases. I'd rather the storage plugin handle it so that it doesn't need to be
reimplemented for multiple plugins. Additionally it will probably need some
specific knowledge of the backend to find/clean the leases

However, there may be additional handling to do on lease cleanup. At least if
there is IP allocation, IPs (may) need to be freed. I can think of 2 solutions:

  • The lease contains an optional Allocator from which the IP(s) were obtained
    (q: can we have multiple IPs in a single lease from multiple allocators ?
    how do we handle that then)
  • The lease contains a callback to free it (interface to be defined. Would you
    pass the entire lease object ? How do you know which allocator to use to free it ?)

Anyway, First Draft

const (
	CidHWAddress = iota
	CidOpt61
	CidDUID
)

// clientID I'm not sure about and don't like too much
// We'd basically be using this as a tagged enum
type ClientID struct {
	// Variant will be one of a few constants identifying types of clientIDs
	Variant uint8
	// data here is a string only used as a read-only []byte that we can use to index maps
	Data string
}

// Lease holds data for a single lease to a client
type Lease struct {
	// Elements is a type generic enough that we can hold any known type of
	// lease (one or multiple IPs or prefixes)
	Elements []net.IPNet

	// Expire is the expiration date of the lease
	Expire time.Time

	// Owner keeps a reference to the plugin that inserted this.
	// It may be used for filtering leases and not touching those from other plugins
	Owner *plugins.Plugin

	// ExpireAction is the callback invoked on lease expiration. It receives
	// Elements and Expire as parameters
	ExpireAction func(elements []net.IPNet, expiredAt time.Time)

	// Here we may need to add something like (and pass it to ExpireAction at least)
	// AdditionalData interface{}
}

type Token interface{}

type LeaseStorage interface{
	// Lookup obtains the leases for a client and prepares an update to them
	Lookup(ClientID) ([]Lease, Token, error)

	// Update attempts to update the leases for ClientID.
	// It may fail and invalidate the Token, after which Lookup() needs to be
	// performed again (and in general the whole operation restarted)
	// On success, the Token is invalidated
	// It may also fail without invalidating the token and be retried
	Update(ClientID, []Lease, Token) error

	// ReleaseToken discards an existing token, after which it can't be used in
	// an Update() anymore
	ReleaseToken(Token) error

	// Possibly, if especially useful, a read that only reads and doesn't create a token:
	// ReadOnlyLookup(ClientID) ([]Lease, error)
}

Offer a Close or Shutdown interface to allow close DHCP server

Hi,

I am using coredhcp in multi-thread mode, I am able to create, Start() a DHCP server and Wait() for packets.
However, I want to end this thread with DHCP shutdown/close gracefully. while my my main function can continue to do other tasks.

So, I'd like to request a Close() or Shutdown() method which can make Wait() exit gracefully without error.

Thank you.

Caddy 2 app

I remember hearing about this project a while ago, and I think it's really cool! I like that it's inspired by CoreDNS, which is inspired by Caddy.

Caddy v2 is almost ready, and has greatly improved support for serving things other than just HTTP. It'd be great to see a DHCP app for Caddy 2!

Caddy 2 apps inherently benefit from a real-time, on-line configuration API and automatic config documentation so you won't have to worry about those parts. Basically you just make your structs, bring over the DHCP server logic, and then wire it up to Caddy (~20 lines of code).

I think it makes a lot of sense for this to be a Caddy plugin. Let me know if I can help in any way!

Adding mutex protection in Handler4 Handler6 to avoid concurrent access

Hi,

I have been using the coredhcp server for some learning purpose and I was doing some performance tests using
"perfdhcp" tool. I saw there were race conditions hit in the Handler4 where there were concurrent read write access to the map of lease records. I now know that map is not good for concurrent access. So I tested by adding a minor change of locking this path with a &sync.mutex. And I have not hit the race since.

Have you gone through the concurrency consideration in any future releases ?

I saw that the server either simply fails to process any requests when the race hits, or performs smoothly for the entire duration of the tests.
[2020-07-13T01:00:13+05:30] INFO plugins/range: found IP address 192.168.245.54 for MAC 00:0c:01:02:03:04
concurrent map writes
fatal error: concurrent map writes

root@ngadre-Inspiron-3542:~/go/src/github.com/coredhcp# perfdhcp -l veth11
Running: perfdhcp -l veth11
^CRate statistics
Rate: 0 4-way exchanges/second
Statistics for: DISCOVER-OFFER
sent packets: 498055
received packets: 0
drops: 498055

min delay: inf ms
avg delay: Delay summary unavailable! No packets received.

Statistics for: REQUEST-ACK
sent packets: 0
received packets: 0
drops: 0

min delay: inf ms
avg delay: Delay summary unavailable! No packets received.

With Mutex protection:

root@ngadre-Inspiron-3542:~/vethDHCP# perfdhcp -l veth11
Running: perfdhcp -l veth11
^CRate statistics
Rate: 3360.67 4-way exchanges/second
Statistics for: DISCOVER-OFFER
sent packets: 85109
received packets: 85106
drops: 3

min delay: 0.091 ms
avg delay: 1.201 ms
max delay: 34.907 ms
std deviation: 3.124 ms
collected packets: 1

Statistics for: REQUEST-ACK
sent packets: 85106
received packets: 85036
drops: 70

min delay: 0.096 ms
avg delay: 1.008 ms
max delay: 28.306 ms
std deviation: 2.407 ms
collected packets: 70

No windows support due to 3rd party package restrictions.

Trying to compile for windows fails because dependencies to "github.com/u-root/u-root/pkg/rand" (from the locally referenced package: "github.com/insomniacslk/dhcp") does not support any windows builds. It has build constraints on *nix systems only in order to use a crypto-safe random number generator (which there are options for windows). This forces coredhcp to run on *nix systems only.

I'm developing on a windows machine and intend to deploy to a debian server, so I could really just use docker locally for development. That being said, is this a strictly *nix application? Any reason why it shouldn't be ran on windows?

Writing this up... I realize this may be more of an insomniacslk/dhcp bug, but it still affects this package too.

Broken retracted dep.

Unfortunately, most projects have moved to go.mod -- GOPATH and git submodules would have been better.
As a result, someone is using the retract feature here:

https://github.com/u-root/u-root/blob/793a1c12ac7f849185ec7dc927cf8ae9e5ad7bc4/go.mod#L71

This breaks the builds for anyone using this project. See here:

coredhcp/go.sum

Line 264 in a2552c5

github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY=

Please upgrade your deps.

Thanks!

support for static DHCP leases

Hi, I want to use coredhcp to serve static leases, instead of ranges of IPs. I adjusted the range plugin to support this, when it's invoked as:

- range: leases.txt 60s

omitting the start and end IP, where each line in leases.txt is in the form of <MAC address> <IP address>. When a host sends a discover message and its MAC address is not in the list, it will not get a lease and a warning is logged.

While I'm fine sending in a PR for this, I can imagine creating a separate plugin for this would be preferred, if only because the plugin is called range right now and that doesn't really translate into anything only serving static leases.

Alternatively, a separatestaticlease plugin is probably better. But I have some questions there:

  • could I make the plugin require the leasetime plugin to be configured so I don't depend on a separate lease time configured per lease (while also not that big of an issue)
  • could I make sure the staticlease plugin is called before the range plugin? That way I could support both plugins simultaneously: if no static lease could be applied, a dynamically assigned address could still be served.

What are your thoughts about this?

Refactor handler

I want to refactor the way handlers work so that a handler is responsible for calling the next handler in the chain.

handler.go could end up being something like this:

type NextHander func() bool
type Handler6 func(req, resp *dhcpv6.DHCPv6, next NextHandler) (bool)
type Handler4 func(req, resp *dhcpv4.DHCPv4, next NextHandler) (bool)

And an example plugin could be something like this:

func exampleHandler6(req, resp *dhcpv6.DHCPv6, next NextHandler) (bool) {
	return next()
}

func exampleHandler4(req, resp *dhcpv4.DHCPv4, next NextHandler) (bool) {
	start := time.Now()
	result := next()
	elapsed := time.Now().Sub(start)
	log.Println("request duration:", elapsed)
	return result
}

This would allow handler code to be executed after the next handler has been called. In the example above, it supports the capture of statistics.

@insomniacslk @pmazzini could I get your feedback on this please?

in use address being offered to new host

Probably need to double check this, but I think I was running into an issue where coredhcp was offering an already used address when the range was full. I'm not sure if the appropriate behavior is to not send an offer or something else.

Plugin logging on registration can't be made silent

Hi,

When the plugins are init(), they log the registration:

[2020-02-06T14:47:46+01:00]  INFO plugins: Registering plugin "dns"
[2020-02-06T14:47:46+01:00]  INFO plugins: Registering plugin "file"
...

Unfortunately, I can't see a way to silent it, since init() is called early, before the program has the chance to change logrus behaviour. Please advise.

dynamic config file location?

Slightly related to #78; but I think it would be great if the program is able to receive the config file location via flags, rather than preempting the location for the users (./config.yml, $HOME/.coredhcp/config.yml, /etc/coredhcp/config.yml).
For example, I should be able to start the app with coredhcp -c /tmp/config.test.yaml.
Not sure, but I think many users would benefit from this approach.

Change "interface" to optional and let DHCP listens on all interfaces in case of no interface offered

Hello,

My use case is pretty simple that I only response the static leases. Which MAC is known by the dhcp server. So, I don't matter which interface the Discover message incoming, but just check the MAC is there and then will reply the DHCP Offer message.
So, I don't need to specify the interface and want to listen on all interface.

I've tried allow the interface is empty in the config Load(), and it works well. (I tried IPv4)

Could we change code to allow interface optional for this?

Vendor Option plugin

Hi there,

I'm interested in adding support for vendor specific options, as specified in RFCs 2132, 3925 et al. and wanted to gauge the interest for this as an 'official' plugin, and also to confirm that work on this is not already happening. I've only briefly started thinking about how this might work, so I don't have any code or design notes to show yet.

Thanks

Listening on both multicast and unicast doesn't work (dhcpv6)

in #28 and insomniacslk/dhcp#278, connection handling and joining multicast groups was refactored. However, it's not possible (at least in linux) to listen on a non-wildcard unicast address, and join multicast groups. If you try now in coredhcp, you'll see the setsockopt call in strace but no traffic received on the multicast address, if there is a listen stanza with a unicast address in config.yml. So this:

server6:
    interface: eth0
    listen: 2001:db8:a::2

Only receives packets for the unicast address and not for ff02::1:2%eth0, even though the group is joined successfully: (from strace log:)

setsockopt(3, SOL_IPV6, MCAST_JOIN_GROUP, {gr_interface=if_nametoindex("eth0"), gr_group={sa_family=AF_INET6, sin6_port=htons(0), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "ff02::1:2", &sin6_addr), sin6_scope_id=0}}, 136)         = 0

Left column describes what you listen on, header describes how many multicast groups you join, table describes what traffic you end up receiving

Join > Listen v None One Multiple
Unicast Unicast only Unicast only Unicast only
Multicast None Multicast if it matches the listening address Multicast, only groups matching the listening address
Wildcard Unicast only Unicast + Multicast Unicast + Multicast

Notably, there is no way to listen on a specific unicast address (not wildcard) and receive multicast traffic on the same socket.

I would fix this by implementing a more generic listen that can receive multiple addresses:

  • By default, it should listen to both RFC-defined multicast addresses (Ideally it should not accept unicast in this mode, but go doesn't let you do that and forces you to bind on [::] if you want any multicast, see [1], so we're forced to always bind to wildcard)
  • Adding one (or more) addresses in listen opens separate sockets to listen on the additional addresses, unicast or multicast without distinction
  • A separate option can be used to disable default multicast addresses (multicast: no ?)
  • Remove the interface configuration option, to fold it into the specific listen stanzas using the standard addr%iface notation (mandatory for link-local, recommended for multicast, not necessary for global unicast)

Example:

server6: 
    listen: 2001:db8::1 fe80::a%eth0 ff08::1:3%eth1
    multicast: no

server4:
    listen: 0.0.0.0%eth0 192.0.2.1 203.0.113.1

note: ipv4 users would need to replace interface: <iface> with listen: 0.0.0.0%<iface>

I intend to implement this once / if we agree on the details

[1]: Unfortunately, go doesn't let you listen on a specific multicast address and replaces the provided address with the wildcard address in order to be "helpful": sock_posix.go#L209

Enforce copyright header

Using github.com/u-root/u-root/tools/checklicenses with config

{
    "gopkg": "github.com/coredhcp/coredhcp",
    "licenses": [
        [
            "^// Copyright 2015-2018 the CoreDHCP Authors\\. All rights reserved",
            "// This source code is licensed under the MIT license found in the",
            "// LICENSE file in the root directory of this source tree\\."
        ]
    ],
    "accept": [
        ".*\\.go"
    ],
    "reject": []
}

[Feature Request] Support ntp-server option (or arbitrary options?)

The current design seems like it necessitates a plugin for every potential DHCP option, which is interesting but ultimately inflexible.

My near-term need is to pass ntp-server to my DHCP clients, and it looks like the easiest path would be to take the dns plugin and make an ntp version of it, since both are trivial options providing IP addresses.

This RFE is intended to capture the lack of ntp-server option support, and raise the idea that a generic option name/number + arguments plugin would greatly extend the usability of CoreDHCP.

Listen on a specific interface

Is there a way to force the server to listen to a specific interface ? I'm not seeing anything about this in the README.MD and example files

Performance comparison with other dhcp clients

Hey, thanks for the project, it sounds interesting, is there any table comparison with other dhcp clients such as dh-client, dhcpcd or systemd-networkd (interested only in dhcp mode)?

Cannot build on Windows

While installing this using PowerShell on Windows:

# go install 'github.com/coredhcp/coredhcp/cmds/coredhcp@dcca4ae19a45f337a47963c45206a550d139a313'
go build github.com/u-root/u-root/pkg/rand: build constraints exclude all Go files in C:\Users\rgl\go\pkg\mod\github.com\u-root\[email protected]+incompatible\pkg\rand

# $LASTEXITCODE
1

This was supposed to be fixed in:

But it seems this repository is still not picking the corrected dhcp library version.

Remove global state

One of the many good things of coredns is how easy it is to embed it into another program.
Coredhcp could benefit to do the same thing by removing all global state (global variables) and expose a NewServer method.
It could also increase project adoption among developers.

website has broken links to config.yml.example

https://coredhcp.io/README.md

<p>For more complex examples, like how to listen on specific interfaces and configure other plugins, see <a href="cmds/coredhcp/config.yml.example">config.yml.example</a>.</p>
<p>Once you have a working configuration in <code>config.yml</code> (see <a href="cmds/coredhcp/config.yml.example">config.yml.example</a>), you can build and run the server:</p>

Both links are broken. Github repo README has a working link to https://github.com/coredhcp/coredhcp/blob/master/cmds/coredhcp/config.yml.example

Handling relay-forwarded messages is error-prone

in #49 I had to fix some logic in 2 plugins for handling relayed messages. Since the full request message is passed to the plugin handlers, in most cases they have to unwind the relay-forward stack of encapsulated messages to get to the options of the inner message. This is error prone because most people won't think to test in relayed contexts (esp. since creating a test harness for relayed contexts is kinda complex).

Passing the inner message to the handlers is probably a bad idea since it removes some valuable information (eg ExtractMac is much less powerful) and outright prevents some types of plugins from being written (eg choosing an ip range based on the network segment of the client)
Even in the current scenario, the link-address and peer-address for the current server are unavailable to plugins (preventing, for example, writing a relay plugin)

I have a few ideas to make this less dangerous and more useful, but there are probably others:

  • Change the handlers to accept a more generic context interface than just the request message. For example this could expose the inner message directly, and the full relay chain separately, while being (more) easily extensible in the future by adding functions to the interface. This requires changing all the current handlers, but there aren't that many. rough example:
// Request transmits context information on the request received by the server
type Request interface{
	// InnerMessage is the request message received, stripped of all relay-forw or relay-repl information
	InnerMessage() *dhcpv6.Message
	// ForwardChain is the list of relays the message passed through
	ForwardChain() []struct{PeerAddress net.IP; LinkAddress net.IP}

	// PeerAddr returns the address of the client or relay agent from which the message was received
	PeerAddr() net.IP
}
  • Pass the request message encapsulated in a synthetic relay-forward message, as if the current server relayed the message to itself. This makes the peer-address and link-address available to plugins, and ensures all plugins always see only relayed messages, so that any kind of testing at all will show the issue if decapsulation is not handled.

"use of closed network connection" errror returned after Close() called

Hi experts,

I know this is expected by current and I can ignore this error in my main function. However, it is really noisy that this log will always get printed. This log get printed by coredhcp and I hope we can ignore this expected error and not print it.

[2020-05-09T09:42:19+08:00] INFO server: Error reading from connection: read udp 0.0.0.0:67: raw-read udp 0.0.0.0:67: use of closed network connection

I have a private fix for this in my forked repo, if you think this fix is reasonable, I can create a pull request to here. Please suggest.
guo1017138@2c39480

Redesign configuration file syntax

The current configuration file syntax is powerful but it exposes too much of the implementation details to the user, and offloads decision chaining in a way that can be hard to predict if the configuration grows significantly. We agree that we want a more user-friendly yet powerful syntax, and that it should be declarative.

@Natolumin and I have thrown a bunch of ideas on https://gist.github.com/Natolumin/2acf759a51becb73080c244b6867d5d9 (these are not formal proposals though) that we would like to discuss more broadly either here or on #coredhcp on gophers.slack.com .

CC @pmazzini @mdlayher for more input, and anyone else feel free to jump in the conversation.

plugins/file: Panic when importing file plugin

When I do go get github.com/coredhcp/coredhcp or when I run a go program that imports "github.com/coredhcp/coredhcp/plugins/file", I always get the following panic message:

../../../github.com/coredhcp/coredhcp/plugins/file/plugin.go:163:6: invalid pointer type *dhcpv6.OptBootFileURL for composite literal

What could be the reason for this? I have had no other problems with other packages. I have even tried reinstalling go and clearing my GOPATH folder.

Thank you very much.

Move plugin initialization to main.go

The plugin initialization should not happen in a "magic" init() call in the plugins. Rather, the plugins should expose a registration function that does the plugin set-up and returns plugin name and handlers. The framework should handle the rest.

running Demo error on client

Hello,

I am testing out coredhcp for possible use in a project on my Ubuntu 20.04 system.

I was able to compile it in Go and then copied over the config.ml-example in the coredhcp server director for use to test. After that, I compile the client.

Once that was done, I had to make an empty leases.txt file and then started up the server:

sudo ./coredhcp

and then tried the client:

sudo ./client

but get an error in the client:

:~/go/src/coredhcp/cmds/client$ sudo ./client

[2021-10-29T19:08:59-04:00] INFO main: &{ReadTimeout:3s WriteTimeout:3s LocalAddr:[::1]:546 RemoteAddr:[::1]:547 SimulateRelay:false RelayOptions:[]}
[2021-10-29T19:08:59-04:00] FATAL main: short hardware addrss: less than 4 bytes

Not sure how to fix this?

Also, can coredhcp be compiled for the Windows platform as well?

Thanks in advance

IPv6 address configuration via NDP

Hey all, this looks like a pretty neat project! I see you're primarily targeting DHCPv4/6, which makes sense, but was curious if IPv6 address configuration via SLAAC using NDP router advertisements could potentially be in scope for the project as well.

It's been my experience that SLAAC is more common in IPv6 since you don't necessarily have to strictly control which machines get which addresses and etc. It could also be useful even in a simple capacity: sending router advertisements with the "managed" flag to inform clients that they should use DHCPv6 instead of SLAAC.

If these ideas are interesting, I've even got a Go package that should do most of the work! https://github.com/mdlayher/ndp

Let me know what your plans are!

Lack of logging for request handling

Hi,

I seem to have issues using coredhcp but its difficult to tell what the specific problem is as the output of the server simply says "Handling request from 0.0.0.0:68" in an infinite loop whilst i try to connect from another dhcp client. It would be nice to have the server log the results of any "request handling" so it simpler to detect a failure to provide an address and the reason if possible.

Concurrent DHCP Servers and IP Conflicts

Is it possible to have multiple concurrent coredhcpservers using the same file_leases.txt file, or would I need multiple coredhcp service different ranges for this to work?

I'm wondering how to integrate this with dhcplb

Listen on multiple interfaces

We should allow listening on multiple interfaces to enable DHCP on systems with multiple NICs (e.g. a home router with two or more wifi and/or fixed eth ports).
Can be temporarily worked around spinning up multiple instances, but only if the IPAM logic is external (e.g. with the redis or netbox plugins), so it'd be great to have it built-in at some point

etcd plugin

It would be great if leases could be stored in etcd for HA setups.

Build fail

Hi there,

Thanks for providing coredhcp.

I am facing a build issue while building master:

 ~/code/g/src/coredhcp/cmds/coredhcp
% go build -v
net
github.com/insomniacslk/dhcp/dhcpv4
# github.com/insomniacslk/dhcp/dhcpv4
/home/firefly/go/pkg/mod/github.com/insomniacslk/[email protected]/dhcpv4/dhcpv4.go:267:9: undefined: uio.NewBigEndianBuffer
/home/firefly/go/pkg/mod/github.com/insomniacslk/[email protected]/dhcpv4/dhcpv4.go:457:17: undefined: uio.Lexer
/home/firefly/go/pkg/mod/github.com/insomniacslk/[email protected]/dhcpv4/dhcpv4.go:468:9: undefined: uio.NewBigEndianBuffer
/home/firefly/go/pkg/mod/github.com/insomniacslk/[email protected]/dhcpv4/option_archtype.go:23:9: undefined: uio.NewBigEndianBuffer
/home/firefly/go/pkg/mod/github.com/insomniacslk/[email protected]/dhcpv4/option_archtype.go:45:9: undefined: uio.NewBigEndianBuffer
/home/firefly/go/pkg/mod/github.com/insomniacslk/[email protected]/dhcpv4/option_broadcast_address.go:19:9: undefined: uio.NewBigEndianBuffer
/home/firefly/go/pkg/mod/github.com/insomniacslk/[email protected]/dhcpv4/option_ip_address_lease_time.go:18:9: undefined: uio.NewBigEndianBuffer
/home/firefly/go/pkg/mod/github.com/insomniacslk/[email protected]/dhcpv4/option_ip_address_lease_time.go:30:9: undefined: uio.NewBigEndianBuffer
/home/firefly/go/pkg/mod/github.com/insomniacslk/[email protected]/dhcpv4/option_ips.go:15:9: undefined: uio.NewBigEndianBuffer
/home/firefly/go/pkg/mod/github.com/insomniacslk/[email protected]/dhcpv4/options.go:233:29: undefined: uio.Lexer
/home/firefly/go/pkg/mod/github.com/insomniacslk/[email protected]/dhcpv4/option_ips.go:15:9: too many errors

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.