add all files from Hong
This commit is contained in:
5
cmds/client/README.md
Normal file
5
cmds/client/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# DHCPv6 debug client
|
||||
|
||||
This is a simple dhcpv6 client for use as a debugging tool with coredhcp
|
||||
|
||||
***This is not a general-purpose DHCP client. This is only a testing/debugging tool for developing CoreDHCP***
|
||||
61
cmds/client/main.go
Normal file
61
cmds/client/main.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2018-present 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.
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
* Sample DHCPv6 client to test on the local interface
|
||||
*/
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"net"
|
||||
|
||||
"github.com/coredhcp/coredhcp/logger"
|
||||
"github.com/insomniacslk/dhcp/dhcpv6"
|
||||
"github.com/insomniacslk/dhcp/dhcpv6/client6"
|
||||
"github.com/insomniacslk/dhcp/iana"
|
||||
)
|
||||
|
||||
var log = logger.GetLogger("main")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
var macString string
|
||||
if len(flag.Args()) > 0 {
|
||||
macString = flag.Arg(0)
|
||||
} else {
|
||||
macString = "00:11:22:33:44:55"
|
||||
}
|
||||
|
||||
c := client6.NewClient()
|
||||
c.LocalAddr = &net.UDPAddr{
|
||||
IP: net.ParseIP("::1"),
|
||||
Port: 546,
|
||||
}
|
||||
c.RemoteAddr = &net.UDPAddr{
|
||||
IP: net.ParseIP("::1"),
|
||||
Port: 547,
|
||||
}
|
||||
log.Printf("%+v", c)
|
||||
|
||||
mac, err := net.ParseMAC(macString)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
duid := dhcpv6.DUIDLLT{
|
||||
HWType: iana.HWTypeEthernet,
|
||||
Time: dhcpv6.GetTime(),
|
||||
LinkLayerAddr: mac,
|
||||
}
|
||||
|
||||
conv, err := c.Exchange("lo", dhcpv6.WithClientID(&duid))
|
||||
for _, p := range conv {
|
||||
log.Print(p.Summary())
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
40
cmds/coredhcp-generator/README.md
Normal file
40
cmds/coredhcp-generator/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
## CoreDHCP Generator
|
||||
|
||||
`coredhcp-generator` is a tool used to build CoreDHCP with the plugins you want.
|
||||
|
||||
Why is it even needed? Go is a compiled language with no dynamic loading
|
||||
support. In order to load a plugin, it has to be compiled in. We are happy to
|
||||
provide a standard [main.go](/cmds/coredhcp/main.go), and at the same time we
|
||||
don't want to include plugins that not everyone would use, otherwise the binary
|
||||
size would grow without control.
|
||||
|
||||
You can use `coredhcp-generator` to generate a `main.go` that includes all the
|
||||
plugins you wish. Just use it as follows:
|
||||
|
||||
```
|
||||
$ ./coredhcp-generator --from core-plugins.txt
|
||||
2019/11/21 23:32:04 Generating output file '/tmp/coredhcp547019106/coredhcp.go' with 7 plugin(s):
|
||||
2019/11/21 23:32:04 1) github.com/coredhcp/coredhcp/plugins/file
|
||||
2019/11/21 23:32:04 2) github.com/coredhcp/coredhcp/plugins/lease_time
|
||||
2019/11/21 23:32:04 3) github.com/coredhcp/coredhcp/plugins/netmask
|
||||
2019/11/21 23:32:04 4) github.com/coredhcp/coredhcp/plugins/range
|
||||
2019/11/21 23:32:04 5) github.com/coredhcp/coredhcp/plugins/router
|
||||
2019/11/21 23:32:04 6) github.com/coredhcp/coredhcp/plugins/server_id
|
||||
2019/11/21 23:32:04 7) github.com/coredhcp/coredhcp/plugins/dns
|
||||
2019/11/21 23:32:04 Generated file '/tmp/coredhcp547019106/coredhcp.go'. You can build it by running 'go build' in the output directory.
|
||||
```
|
||||
|
||||
You can also specify the plugin list on the command line, or mix it with
|
||||
`--from`:
|
||||
```
|
||||
$ ./coredhcp-generator --from core-plugins.txt \
|
||||
github.com/coredhcp/plugins/redis
|
||||
```
|
||||
|
||||
Notice that it created a file called `coredhcp.go` in a temporary directory. You
|
||||
can now `go build` that file and have your own custom CoreDHCP.
|
||||
|
||||
## Bugs
|
||||
|
||||
CoreDHCP uses Go versioned modules. The generated file does not do that yet. We
|
||||
will add this feature soon.
|
||||
15
cmds/coredhcp-generator/core-plugins.txt
Normal file
15
cmds/coredhcp-generator/core-plugins.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
github.com/coredhcp/coredhcp/plugins/autoconfigure
|
||||
github.com/coredhcp/coredhcp/plugins/dns
|
||||
github.com/coredhcp/coredhcp/plugins/file
|
||||
github.com/coredhcp/coredhcp/plugins/ipv6only
|
||||
github.com/coredhcp/coredhcp/plugins/leasetime
|
||||
github.com/coredhcp/coredhcp/plugins/mtu
|
||||
github.com/coredhcp/coredhcp/plugins/netmask
|
||||
github.com/coredhcp/coredhcp/plugins/nbp
|
||||
github.com/coredhcp/coredhcp/plugins/prefix
|
||||
github.com/coredhcp/coredhcp/plugins/range
|
||||
github.com/coredhcp/coredhcp/plugins/router
|
||||
github.com/coredhcp/coredhcp/plugins/serverid
|
||||
github.com/coredhcp/coredhcp/plugins/searchdomains
|
||||
github.com/coredhcp/coredhcp/plugins/sleep
|
||||
github.com/coredhcp/coredhcp/plugins/staticroute
|
||||
104
cmds/coredhcp-generator/coredhcp.go.template
Normal file
104
cmds/coredhcp-generator/coredhcp.go.template
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright 2018-present 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.
|
||||
|
||||
{{/* This file is the template source. The following comment obviously doesn't apply here */ -}}
|
||||
// This is a generated file, edits should be made in the corresponding source file
|
||||
// And this file regenerated using `coredhcp-generator --from core-plugins.txt`
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/coredhcp/coredhcp/config"
|
||||
"github.com/coredhcp/coredhcp/logger"
|
||||
"github.com/coredhcp/coredhcp/server"
|
||||
|
||||
"github.com/coredhcp/coredhcp/plugins"
|
||||
{{- range $plugin := .}}
|
||||
{{- /* We import all plugins as pl_<pluginname> to avoid conflicts with reserved keywords */}}
|
||||
{{importname $plugin}} "{{$plugin}}"
|
||||
{{- end}}
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var (
|
||||
flagLogFile = flag.StringP("logfile", "l", "", "Name of the log file to append to. Default: stdout/stderr only")
|
||||
flagLogNoStdout = flag.BoolP("nostdout", "N", false, "Disable logging to stdout/stderr")
|
||||
flagLogLevel = flag.StringP("loglevel", "L", "info", fmt.Sprintf("Log level. One of %v", getLogLevels()))
|
||||
flagConfig = flag.StringP("conf", "c", "", "Use this configuration file instead of the default location")
|
||||
flagPlugins = flag.BoolP("plugins", "P", false, "list plugins")
|
||||
)
|
||||
|
||||
var logLevels = map[string]func(*logrus.Logger){
|
||||
"none": func(l *logrus.Logger) { l.SetOutput(io.Discard) },
|
||||
"debug": func(l *logrus.Logger) { l.SetLevel(logrus.DebugLevel) },
|
||||
"info": func(l *logrus.Logger) { l.SetLevel(logrus.InfoLevel) },
|
||||
"warning": func(l *logrus.Logger) { l.SetLevel(logrus.WarnLevel) },
|
||||
"error": func(l *logrus.Logger) { l.SetLevel(logrus.ErrorLevel) },
|
||||
"fatal": func(l *logrus.Logger) { l.SetLevel(logrus.FatalLevel) },
|
||||
}
|
||||
|
||||
func getLogLevels() []string {
|
||||
var levels []string
|
||||
for k := range logLevels {
|
||||
levels = append(levels, k)
|
||||
}
|
||||
return levels
|
||||
}
|
||||
|
||||
var desiredPlugins = []*plugins.Plugin{
|
||||
{{- range $plugin := .}}
|
||||
&{{importname $plugin}}.Plugin,
|
||||
{{- end}}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if *flagPlugins {
|
||||
for _, p := range desiredPlugins {
|
||||
fmt.Println(p.Name)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
log := logger.GetLogger("main")
|
||||
fn, ok := logLevels[*flagLogLevel]
|
||||
if !ok {
|
||||
log.Fatalf("Invalid log level '%s'. Valid log levels are %v", *flagLogLevel, getLogLevels())
|
||||
}
|
||||
fn(log.Logger)
|
||||
log.Infof("Setting log level to '%s'", *flagLogLevel)
|
||||
if *flagLogFile != "" {
|
||||
log.Infof("Logging to file %s", *flagLogFile)
|
||||
logger.WithFile(log, *flagLogFile)
|
||||
}
|
||||
if *flagLogNoStdout {
|
||||
log.Infof("Disabling logging to stdout/stderr")
|
||||
logger.WithNoStdOutErr(log)
|
||||
}
|
||||
config, err := config.Load(*flagConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load configuration: %v", err)
|
||||
}
|
||||
// register plugins
|
||||
for _, plugin := range desiredPlugins {
|
||||
if err := plugins.RegisterPlugin(plugin); err != nil {
|
||||
log.Fatalf("Failed to register plugin '%s': %v", plugin.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// start server
|
||||
srv, err := server.Start(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := srv.Wait(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
144
cmds/coredhcp-generator/main.go
Normal file
144
cmds/coredhcp-generator/main.go
Normal file
@@ -0,0 +1,144 @@
|
||||
// Copyright 2018-present 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTemplateFile = "coredhcp.go.template"
|
||||
importBase = "github.com/coredhcp/coredhcp/"
|
||||
)
|
||||
|
||||
var (
|
||||
flagTemplate = flag.StringP("template", "t", defaultTemplateFile, "Template file name")
|
||||
flagOutfile = flag.StringP("outfile", "o", "", "Output file path")
|
||||
flagFromFile = flag.StringP("from", "f", "", "Optional file name to get the plugin list from, one import path per line")
|
||||
)
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"importname": func(importPath string) (string, error) {
|
||||
parts := strings.Split(importPath, "/")
|
||||
if len(parts) < 1 {
|
||||
return "", fmt.Errorf("no components found in import path '%s'", importPath)
|
||||
}
|
||||
return "pl_" + parts[len(parts)-1], nil
|
||||
},
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(flag.CommandLine.Output(),
|
||||
"%s [-template tpl] [-outfile out] [-from pluginlist] [plugin [plugin...]]\n",
|
||||
os.Args[0],
|
||||
)
|
||||
flag.PrintDefaults()
|
||||
fmt.Fprintln(flag.CommandLine.Output(), ` plugin
|
||||
Plugin name to include, as go import path.
|
||||
Short names can be used for builtin coredhcp plugins (eg "serverid")`)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
|
||||
data, err := os.ReadFile(*flagTemplate)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read template file '%s': %v", *flagTemplate, err)
|
||||
}
|
||||
t, err := template.New("coredhcp").Funcs(funcMap).Parse(string(data))
|
||||
if err != nil {
|
||||
log.Fatalf("Template parsing failed: %v", err)
|
||||
}
|
||||
plugins := make(map[string]bool)
|
||||
for _, pl := range flag.Args() {
|
||||
pl := strings.TrimSpace(pl)
|
||||
if pl == "" {
|
||||
continue
|
||||
}
|
||||
if !strings.ContainsRune(pl, '/') {
|
||||
// A bare name was specified, not a full import path.
|
||||
// Coredhcp plugins aren't in the standard library, and it's unlikely someone
|
||||
// would put them at the base of $GOPATH/src.
|
||||
// Assume this is one of the builtin plugins. If needed, use the -from option
|
||||
// which always requires (and uses) exact paths
|
||||
|
||||
// XXX: we could also look into github.com/coredhcp/plugins
|
||||
pl = importBase + pl
|
||||
}
|
||||
plugins[pl] = true
|
||||
}
|
||||
if *flagFromFile != "" {
|
||||
// additional plugin names from a text file, one line per plugin import
|
||||
// path
|
||||
fd, err := os.Open(*flagFromFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read file '%s': %v", *flagFromFile, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := fd.Close(); err != nil {
|
||||
log.Printf("Error closing file '%s': %v", *flagFromFile, err)
|
||||
}
|
||||
}()
|
||||
sc := bufio.NewScanner(fd)
|
||||
for sc.Scan() {
|
||||
pl := strings.TrimSpace(sc.Text())
|
||||
if pl == "" {
|
||||
continue
|
||||
}
|
||||
plugins[pl] = true
|
||||
}
|
||||
if err := sc.Err(); err != nil {
|
||||
log.Fatalf("Error reading file '%s': %v", *flagFromFile, err)
|
||||
}
|
||||
}
|
||||
if len(plugins) == 0 {
|
||||
log.Fatalf("No plugin specified!")
|
||||
}
|
||||
outfile := *flagOutfile
|
||||
if outfile == "" {
|
||||
tmpdir, err := os.MkdirTemp("", "coredhcp")
|
||||
if err != nil {
|
||||
log.Fatalf("Cannot create temporary directory: %v", err)
|
||||
}
|
||||
outfile = path.Join(tmpdir, "coredhcp.go")
|
||||
}
|
||||
|
||||
log.Printf("Generating output file '%s' with %d plugin(s):", outfile, len(plugins))
|
||||
idx := 1
|
||||
for pl := range plugins {
|
||||
log.Printf("% 3d) %s", idx, pl)
|
||||
idx++
|
||||
}
|
||||
outFD, err := os.OpenFile(outfile, os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create output file '%s': %v", outfile, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := outFD.Close(); err != nil {
|
||||
log.Printf("Error while closing file descriptor for '%s': %v", outfile, err)
|
||||
}
|
||||
}()
|
||||
// WARNING: no escaping of the provided strings is done
|
||||
pluginList := make([]string, 0, len(plugins))
|
||||
for pl := range plugins {
|
||||
pluginList = append(pluginList, pl)
|
||||
}
|
||||
sort.Strings(pluginList)
|
||||
if err := t.Execute(outFD, pluginList); err != nil {
|
||||
log.Fatalf("Template execution failed: %v", err)
|
||||
}
|
||||
log.Printf("Generated file '%s'. You can build it by running 'go build' in the output directory.", outfile)
|
||||
fmt.Println(path.Dir(outfile))
|
||||
}
|
||||
167
cmds/coredhcp/config.yml
Normal file
167
cmds/coredhcp/config.yml
Normal file
@@ -0,0 +1,167 @@
|
||||
# CoreDHCP configuration (yaml)
|
||||
|
||||
# In this file, lines starting with "## " represent default values,
|
||||
# while uncommented lines are examples which have no default value
|
||||
|
||||
# The base level configuration has two sections, one for each protocol version
|
||||
# (DHCPv4 and DHCPv6). There is no shared configuration at the moment.
|
||||
# At a high level, both accept the same structure of configuration
|
||||
|
||||
# DHCPv6 configuration
|
||||
#server6:
|
||||
# listen is an optional section to specify how the server binds to an
|
||||
# interface or address.
|
||||
# If unset, the server will join the link-layer multicast group for all
|
||||
# dhcp servers and relays on each interface, as well as the site-scoped
|
||||
# multicast group for all dhcp servers.
|
||||
# Note that in this default configuration the server will not handle
|
||||
# unicast datagrams, and is equivalent to:
|
||||
## listen:
|
||||
## - "[ff02::1:2]"
|
||||
## - "[ff05::1:3]"
|
||||
|
||||
# In general, listen takes a list of addresses, with the general syntax
|
||||
# "[address%interface]:port", where each part is optional.
|
||||
# Omitting the address results in the wildcard address being used
|
||||
# Omitting the interface skips binding the listener to a specific interface
|
||||
# and listens on all interfaces instead
|
||||
# Omitting the port uses the default port for DHCPv6 (547)
|
||||
#
|
||||
# For example:
|
||||
# - "[::]"
|
||||
# Listen on the wildcard address on all interfaces on the default port.
|
||||
# Note that no multicast group will be joined, so this will *not* work with
|
||||
# most clients
|
||||
#
|
||||
# - ":44480"
|
||||
# Listens on the wildcard address on a specific port. This can be used if
|
||||
# you have a relay setup that can contact this server using unicast
|
||||
#
|
||||
# - "[::%eno1]"
|
||||
# Listens on the wildcard address on one interface. This can be used if you
|
||||
# want to spawn multiple servers with different configurations for multiple
|
||||
# interfaces, behind a relay that can use unicast
|
||||
#
|
||||
# There are some special considerations for multicast:
|
||||
# - "[ff02::1:2%eno1]"
|
||||
# Listens on a link-layer multicast address bound to an interface. Also
|
||||
# used to spawn multiple servers, but for clients on the same subnet
|
||||
#
|
||||
# - "[ff05::1:3%eno1]"
|
||||
# Joining a multicast group with an interface allows to skip the default
|
||||
# routing table when responding to clients, which can be useful if
|
||||
# multicast is not otherwise configured system-wide
|
||||
#
|
||||
# - "[ff02::1:2]"
|
||||
# Using a multicast address without an interface will be auto-expanded, so
|
||||
# that it listens on all available interfaces
|
||||
|
||||
|
||||
# plugins is a mandatory section, which defines how requests are handled.
|
||||
# It is a list of maps, matching plugin names to their arguments.
|
||||
# The order is meaningful, as incoming requests are handled by each plugin
|
||||
# in turn. There is no default value for a plugin configuration, and a
|
||||
# plugin that is not mentioned will not be loaded at all
|
||||
#
|
||||
# The following contains examples of the most common, builtin plugins.
|
||||
# External plugins should document their arguments in their own
|
||||
# documentations or readmes
|
||||
#plugins:
|
||||
# server_id is mandatory for RFC-compliant operation.
|
||||
# - server_id: <DUID format> <LL address>
|
||||
# The supported DUID formats are LL and LLT
|
||||
#- server_id: LL 00:de:ad:be:ef:00
|
||||
|
||||
# file serves leases defined in a static file, matching link-layer addresses to IPs
|
||||
# - file: <file name> [autorefresh]
|
||||
# The file format is one lease per line, "<hw address> <IPv6>"
|
||||
# When the 'autorefresh' argument is given, the plugin will try to refresh
|
||||
# the lease mapping during runtime whenever the lease file is updated.
|
||||
#- file: "leases.txt"
|
||||
|
||||
# dns adds information about available DNS resolvers to the responses
|
||||
# - dns: <resolver IP> <... resolver IPs>
|
||||
#- dns: 2001:4860:4860::8888 2001:4860:4860::8844
|
||||
|
||||
# nbp can add information about the location of a network boot program
|
||||
# - nbp: <NBP URL>
|
||||
#- nbp: "http://[2001:db8:a::1]/nbp"
|
||||
|
||||
# prefix provides prefix delegation.
|
||||
# - prefix: <prefix> <allocation size>
|
||||
# prefix is the prefix pool from which the allocations will be carved
|
||||
# allocation size is the maximum size for prefixes that will be allocated to clients
|
||||
# EG for allocating /64 or smaller prefixes within 2001:db8::/48 :
|
||||
#- prefix: 2001:db8::/48 64
|
||||
|
||||
# DHCPv4 configuration
|
||||
server4:
|
||||
# listen is an optional section to specify how the server binds to an
|
||||
# interface or address.
|
||||
# If unset, the server will listen on the broadcast address on all
|
||||
# interfaces, equivalent to:
|
||||
## listen:
|
||||
## - "0.0.0.0"
|
||||
|
||||
# In general, listen takes a list of addresses, with the general syntax
|
||||
# "address%interface:port", where each part is optional.
|
||||
# * Omitting the address results in the wildcard address being used
|
||||
# * Omitting the interface skips binding the listener to a specific interface
|
||||
# and listens on all interfaces instead
|
||||
# * Omitting the port uses the default port for DHCPv4 (67)
|
||||
#
|
||||
# For example:
|
||||
# - ":44480" Listens on a specific port.
|
||||
# - "%eno1" Listens on the wildcard address on one interface.
|
||||
# - "192.0.2.1%eno1:44480" with all parts
|
||||
|
||||
# plugins is a mandatory section, which defines how requests are handled.
|
||||
# It is a list of maps, matching plugin names to their arguments.
|
||||
# The order is meaningful, as incoming requests are handled by each plugin
|
||||
# in turn. There is no default value for a plugin configuration, and a
|
||||
# plugin that is not mentioned will not be loaded at all
|
||||
#
|
||||
# The following contains examples of the most common, builtin plugins.
|
||||
# External plugins should document their arguments in their own
|
||||
# documentations or readmes
|
||||
plugins:
|
||||
# lease_time sets the default lease time for advertised leases
|
||||
# - lease_time: <duration>
|
||||
# The duration can be given in any format understood by go's
|
||||
# "ParseDuration": https://golang.org/pkg/time/#ParseDuration
|
||||
- lease_time: 3600s
|
||||
|
||||
# server_id advertises a DHCP Server Identifier, to help resolve
|
||||
# situations where there are multiple DHCP servers on the network
|
||||
# - server_id: <IP address>
|
||||
# The IP address should be one address where this server is reachable
|
||||
- server_id: 10.10.10.1
|
||||
|
||||
# dns advertises DNS resolvers usable by the clients on this network
|
||||
# - dns: <IP address> <...IP addresses>
|
||||
- dns: 8.8.8.8 8.8.4.4
|
||||
|
||||
# router is mandatory, and advertises the address of the default router
|
||||
# for this network
|
||||
# - router: <IP address>
|
||||
- router: 192.168.1.1
|
||||
|
||||
# netmask advertises the network mask for the IPs assigned through this
|
||||
# server
|
||||
# - netmask: <network mask>
|
||||
- netmask: 255.255.255.0
|
||||
|
||||
# range allocates leases within a range of IPs
|
||||
# - range: <lease file> <start IP> <end IP> <lease duration>
|
||||
# * the lease file is an initially empty file where the leases that are
|
||||
# allocated to clients will be stored across server restarts
|
||||
# * lease duration can be given in any format understood by go's
|
||||
# "ParseDuration": https://golang.org/pkg/time/#ParseDuration
|
||||
- range: leases.txt 10.10.10.100 10.10.10.200 60s
|
||||
|
||||
# staticroute advertises additional routes the client should install in
|
||||
# its routing table as described in RFC3442
|
||||
# - staticroute: <destination>,<gateway> [<destination>,<gateway> ...]
|
||||
# where destination should be in CIDR notation and gateway should be
|
||||
# the IP address of the router through which the destination is reachable
|
||||
# - staticroute: 10.20.20.0/24,10.10.10.1
|
||||
167
cmds/coredhcp/config.yml.example
Normal file
167
cmds/coredhcp/config.yml.example
Normal file
@@ -0,0 +1,167 @@
|
||||
# CoreDHCP configuration (yaml)
|
||||
|
||||
# In this file, lines starting with "## " represent default values,
|
||||
# while uncommented lines are examples which have no default value
|
||||
|
||||
# The base level configuration has two sections, one for each protocol version
|
||||
# (DHCPv4 and DHCPv6). There is no shared configuration at the moment.
|
||||
# At a high level, both accept the same structure of configuration
|
||||
|
||||
# DHCPv6 configuration
|
||||
server6:
|
||||
# listen is an optional section to specify how the server binds to an
|
||||
# interface or address.
|
||||
# If unset, the server will join the link-layer multicast group for all
|
||||
# dhcp servers and relays on each interface, as well as the site-scoped
|
||||
# multicast group for all dhcp servers.
|
||||
# Note that in this default configuration the server will not handle
|
||||
# unicast datagrams, and is equivalent to:
|
||||
## listen:
|
||||
## - "[ff02::1:2]"
|
||||
## - "[ff05::1:3]"
|
||||
|
||||
# In general, listen takes a list of addresses, with the general syntax
|
||||
# "[address%interface]:port", where each part is optional.
|
||||
# Omitting the address results in the wildcard address being used
|
||||
# Omitting the interface skips binding the listener to a specific interface
|
||||
# and listens on all interfaces instead
|
||||
# Omitting the port uses the default port for DHCPv6 (547)
|
||||
#
|
||||
# For example:
|
||||
# - "[::]"
|
||||
# Listen on the wildcard address on all interfaces on the default port.
|
||||
# Note that no multicast group will be joined, so this will *not* work with
|
||||
# most clients
|
||||
#
|
||||
# - ":44480"
|
||||
# Listens on the wildcard address on a specific port. This can be used if
|
||||
# you have a relay setup that can contact this server using unicast
|
||||
#
|
||||
# - "[::%eno1]"
|
||||
# Listens on the wildcard address on one interface. This can be used if you
|
||||
# want to spawn multiple servers with different configurations for multiple
|
||||
# interfaces, behind a relay that can use unicast
|
||||
#
|
||||
# There are some special considerations for multicast:
|
||||
# - "[ff02::1:2%eno1]"
|
||||
# Listens on a link-layer multicast address bound to an interface. Also
|
||||
# used to spawn multiple servers, but for clients on the same subnet
|
||||
#
|
||||
# - "[ff05::1:3%eno1]"
|
||||
# Joining a multicast group with an interface allows to skip the default
|
||||
# routing table when responding to clients, which can be useful if
|
||||
# multicast is not otherwise configured system-wide
|
||||
#
|
||||
# - "[ff02::1:2]"
|
||||
# Using a multicast address without an interface will be auto-expanded, so
|
||||
# that it listens on all available interfaces
|
||||
|
||||
|
||||
# plugins is a mandatory section, which defines how requests are handled.
|
||||
# It is a list of maps, matching plugin names to their arguments.
|
||||
# The order is meaningful, as incoming requests are handled by each plugin
|
||||
# in turn. There is no default value for a plugin configuration, and a
|
||||
# plugin that is not mentioned will not be loaded at all
|
||||
#
|
||||
# The following contains examples of the most common, builtin plugins.
|
||||
# External plugins should document their arguments in their own
|
||||
# documentations or readmes
|
||||
plugins:
|
||||
# server_id is mandatory for RFC-compliant operation.
|
||||
# - server_id: <DUID format> <LL address>
|
||||
# The supported DUID formats are LL and LLT
|
||||
- server_id: LL 00:de:ad:be:ef:00
|
||||
|
||||
# file serves leases defined in a static file, matching link-layer addresses to IPs
|
||||
# - file: <file name> [autorefresh]
|
||||
# The file format is one lease per line, "<hw address> <IPv6>"
|
||||
# When the 'autorefresh' argument is given, the plugin will try to refresh
|
||||
# the lease mapping during runtime whenever the lease file is updated.
|
||||
- file: "leases.txt"
|
||||
|
||||
# dns adds information about available DNS resolvers to the responses
|
||||
# - dns: <resolver IP> <... resolver IPs>
|
||||
- dns: 2001:4860:4860::8888 2001:4860:4860::8844
|
||||
|
||||
# nbp can add information about the location of a network boot program
|
||||
# - nbp: <NBP URL>
|
||||
- nbp: "http://[2001:db8:a::1]/nbp"
|
||||
|
||||
# prefix provides prefix delegation.
|
||||
# - prefix: <prefix> <allocation size>
|
||||
# prefix is the prefix pool from which the allocations will be carved
|
||||
# allocation size is the maximum size for prefixes that will be allocated to clients
|
||||
# EG for allocating /64 or smaller prefixes within 2001:db8::/48 :
|
||||
- prefix: 2001:db8::/48 64
|
||||
|
||||
# DHCPv4 configuration
|
||||
server4:
|
||||
# listen is an optional section to specify how the server binds to an
|
||||
# interface or address.
|
||||
# If unset, the server will listen on the broadcast address on all
|
||||
# interfaces, equivalent to:
|
||||
## listen:
|
||||
## - "0.0.0.0"
|
||||
|
||||
# In general, listen takes a list of addresses, with the general syntax
|
||||
# "address%interface:port", where each part is optional.
|
||||
# * Omitting the address results in the wildcard address being used
|
||||
# * Omitting the interface skips binding the listener to a specific interface
|
||||
# and listens on all interfaces instead
|
||||
# * Omitting the port uses the default port for DHCPv4 (67)
|
||||
#
|
||||
# For example:
|
||||
# - ":44480" Listens on a specific port.
|
||||
# - "%eno1" Listens on the wildcard address on one interface.
|
||||
# - "192.0.2.1%eno1:44480" with all parts
|
||||
|
||||
# plugins is a mandatory section, which defines how requests are handled.
|
||||
# It is a list of maps, matching plugin names to their arguments.
|
||||
# The order is meaningful, as incoming requests are handled by each plugin
|
||||
# in turn. There is no default value for a plugin configuration, and a
|
||||
# plugin that is not mentioned will not be loaded at all
|
||||
#
|
||||
# The following contains examples of the most common, builtin plugins.
|
||||
# External plugins should document their arguments in their own
|
||||
# documentations or readmes
|
||||
plugins:
|
||||
# lease_time sets the default lease time for advertised leases
|
||||
# - lease_time: <duration>
|
||||
# The duration can be given in any format understood by go's
|
||||
# "ParseDuration": https://golang.org/pkg/time/#ParseDuration
|
||||
- lease_time: 3600s
|
||||
|
||||
# server_id advertises a DHCP Server Identifier, to help resolve
|
||||
# situations where there are multiple DHCP servers on the network
|
||||
# - server_id: <IP address>
|
||||
# The IP address should be one address where this server is reachable
|
||||
- server_id: 10.10.10.1
|
||||
|
||||
# dns advertises DNS resolvers usable by the clients on this network
|
||||
# - dns: <IP address> <...IP addresses>
|
||||
- dns: 8.8.8.8 8.8.4.4
|
||||
|
||||
# router is mandatory, and advertises the address of the default router
|
||||
# for this network
|
||||
# - router: <IP address>
|
||||
- router: 192.168.1.1
|
||||
|
||||
# netmask advertises the network mask for the IPs assigned through this
|
||||
# server
|
||||
# - netmask: <network mask>
|
||||
- netmask: 255.255.255.0
|
||||
|
||||
# range allocates leases within a range of IPs
|
||||
# - range: <lease file> <start IP> <end IP> <lease duration>
|
||||
# * the lease file is an initially empty file where the leases that are
|
||||
# allocated to clients will be stored across server restarts
|
||||
# * lease duration can be given in any format understood by go's
|
||||
# "ParseDuration": https://golang.org/pkg/time/#ParseDuration
|
||||
- range: leases.txt 10.10.10.100 10.10.10.200 60s
|
||||
|
||||
# staticroute advertises additional routes the client should install in
|
||||
# its routing table as described in RFC3442
|
||||
# - staticroute: <destination>,<gateway> [<destination>,<gateway> ...]
|
||||
# where destination should be in CIDR notation and gateway should be
|
||||
# the IP address of the router through which the destination is reachable
|
||||
# - staticroute: 10.20.20.0/24,10.10.10.1
|
||||
BIN
cmds/coredhcp/coredhcp
Executable file
BIN
cmds/coredhcp/coredhcp
Executable file
Binary file not shown.
1
cmds/coredhcp/file_leases.txt.example
Normal file
1
cmds/coredhcp/file_leases.txt.example
Normal file
@@ -0,0 +1 @@
|
||||
00:11:22:33:44:55 2001:2::1
|
||||
BIN
cmds/coredhcp/leases.txt
Normal file
BIN
cmds/coredhcp/leases.txt
Normal file
Binary file not shown.
129
cmds/coredhcp/main.go
Normal file
129
cmds/coredhcp/main.go
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2018-present 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.
|
||||
|
||||
// This is a generated file, edits should be made in the corresponding source file
|
||||
// And this file regenerated using `coredhcp-generator --from core-plugins.txt`
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/coredhcp/coredhcp/config"
|
||||
grpcServer "github.com/coredhcp/coredhcp/grpc_server"
|
||||
"github.com/coredhcp/coredhcp/logger"
|
||||
"github.com/coredhcp/coredhcp/server"
|
||||
|
||||
"github.com/coredhcp/coredhcp/plugins"
|
||||
pl_autoconfigure "github.com/coredhcp/coredhcp/plugins/autoconfigure"
|
||||
pl_dns "github.com/coredhcp/coredhcp/plugins/dns"
|
||||
pl_file "github.com/coredhcp/coredhcp/plugins/file"
|
||||
pl_ipv6only "github.com/coredhcp/coredhcp/plugins/ipv6only"
|
||||
pl_leasetime "github.com/coredhcp/coredhcp/plugins/leasetime"
|
||||
pl_mtu "github.com/coredhcp/coredhcp/plugins/mtu"
|
||||
pl_nbp "github.com/coredhcp/coredhcp/plugins/nbp"
|
||||
pl_netmask "github.com/coredhcp/coredhcp/plugins/netmask"
|
||||
pl_prefix "github.com/coredhcp/coredhcp/plugins/prefix"
|
||||
pl_range "github.com/coredhcp/coredhcp/plugins/range"
|
||||
pl_router "github.com/coredhcp/coredhcp/plugins/router"
|
||||
pl_searchdomains "github.com/coredhcp/coredhcp/plugins/searchdomains"
|
||||
pl_serverid "github.com/coredhcp/coredhcp/plugins/serverid"
|
||||
pl_sleep "github.com/coredhcp/coredhcp/plugins/sleep"
|
||||
pl_staticroute "github.com/coredhcp/coredhcp/plugins/staticroute"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var (
|
||||
flagLogFile = flag.StringP("logfile", "l", "", "Name of the log file to append to. Default: stdout/stderr only")
|
||||
flagLogNoStdout = flag.BoolP("nostdout", "N", false, "Disable logging to stdout/stderr")
|
||||
flagLogLevel = flag.StringP("loglevel", "L", "info", fmt.Sprintf("Log level. One of %v", getLogLevels()))
|
||||
flagConfig = flag.StringP("conf", "c", "", "Use this configuration file instead of the default location")
|
||||
flagPlugins = flag.BoolP("plugins", "P", false, "list plugins")
|
||||
)
|
||||
|
||||
var logLevels = map[string]func(*logrus.Logger){
|
||||
"none": func(l *logrus.Logger) { l.SetOutput(io.Discard) },
|
||||
"debug": func(l *logrus.Logger) { l.SetLevel(logrus.DebugLevel) },
|
||||
"info": func(l *logrus.Logger) { l.SetLevel(logrus.InfoLevel) },
|
||||
"warning": func(l *logrus.Logger) { l.SetLevel(logrus.WarnLevel) },
|
||||
"error": func(l *logrus.Logger) { l.SetLevel(logrus.ErrorLevel) },
|
||||
"fatal": func(l *logrus.Logger) { l.SetLevel(logrus.FatalLevel) },
|
||||
}
|
||||
|
||||
func getLogLevels() []string {
|
||||
var levels []string
|
||||
for k := range logLevels {
|
||||
levels = append(levels, k)
|
||||
}
|
||||
return levels
|
||||
}
|
||||
|
||||
var desiredPlugins = []*plugins.Plugin{
|
||||
&pl_autoconfigure.Plugin,
|
||||
&pl_dns.Plugin,
|
||||
&pl_file.Plugin,
|
||||
&pl_ipv6only.Plugin,
|
||||
&pl_leasetime.Plugin,
|
||||
&pl_mtu.Plugin,
|
||||
&pl_nbp.Plugin,
|
||||
&pl_netmask.Plugin,
|
||||
&pl_prefix.Plugin,
|
||||
&pl_range.Plugin,
|
||||
&pl_router.Plugin,
|
||||
&pl_searchdomains.Plugin,
|
||||
&pl_serverid.Plugin,
|
||||
&pl_sleep.Plugin,
|
||||
&pl_staticroute.Plugin,
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if *flagPlugins {
|
||||
for _, p := range desiredPlugins {
|
||||
fmt.Println(p.Name)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
log := logger.GetLogger("main")
|
||||
fn, ok := logLevels[*flagLogLevel]
|
||||
if !ok {
|
||||
log.Fatalf("Invalid log level '%s'. Valid log levels are %v", *flagLogLevel, getLogLevels())
|
||||
}
|
||||
fn(log.Logger)
|
||||
log.Infof("Setting log level to '%s'", *flagLogLevel)
|
||||
if *flagLogFile != "" {
|
||||
log.Infof("Logging to file %s", *flagLogFile)
|
||||
logger.WithFile(log, *flagLogFile)
|
||||
}
|
||||
if *flagLogNoStdout {
|
||||
log.Infof("Disabling logging to stdout/stderr")
|
||||
logger.WithNoStdOutErr(log)
|
||||
}
|
||||
config, err := config.Load(*flagConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load configuration: %v", err)
|
||||
}
|
||||
// register plugins
|
||||
for _, plugin := range desiredPlugins {
|
||||
if err := plugins.RegisterPlugin(plugin); err != nil {
|
||||
log.Fatalf("Failed to register plugin '%s': %v", plugin.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
go grpcServer.Run()
|
||||
|
||||
// start server
|
||||
srv, err := server.Start(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := srv.Wait(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user