added some option handling functions
This commit is contained in:
1
Makefile
1
Makefile
@ -10,6 +10,7 @@ VERSION=1.0.0
|
||||
|
||||
SRCS=\
|
||||
haza.go \
|
||||
opt.go \
|
||||
pkt.go \
|
||||
server.go \
|
||||
sock.go
|
||||
|
22
haza.go
22
haza.go
@ -81,19 +81,19 @@ func Ntoh32(v uint32) uint32 {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
type ByteReader struct {
|
||||
type NetByteReader struct {
|
||||
r *bytes.Reader
|
||||
}
|
||||
|
||||
func NewByteReader(b []byte) *ByteReader {
|
||||
return &ByteReader{ r: bytes.NewReader(b) }
|
||||
func NewNetByteReader(b []byte) *NetByteReader {
|
||||
return &NetByteReader{ r: bytes.NewReader(b) }
|
||||
}
|
||||
|
||||
func (br* ByteReader) ReadByte() (byte, error) {
|
||||
func (br* NetByteReader) ReadByte() (byte, error) {
|
||||
return br.r.ReadByte()
|
||||
}
|
||||
|
||||
func (br* ByteReader) ReadUint16() (uint16, error) {
|
||||
func (br* NetByteReader) ReadUint16() (uint16, error) {
|
||||
var v uint16
|
||||
var err error
|
||||
err = binary.Read(br.r, binary.BigEndian, &v)
|
||||
@ -101,7 +101,7 @@ func (br* ByteReader) ReadUint16() (uint16, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (br* ByteReader) ReadUint32() (uint32, error) {
|
||||
func (br* NetByteReader) ReadUint32() (uint32, error) {
|
||||
var v uint32
|
||||
var err error
|
||||
err = binary.Read(br.r, binary.BigEndian, &v)
|
||||
@ -109,7 +109,7 @@ func (br* ByteReader) ReadUint32() (uint32, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (br* ByteReader) ReadIp4() (net.IP, error) {
|
||||
func (br* NetByteReader) ReadIp4() (net.IP, error) {
|
||||
var buf [4]byte
|
||||
var err error
|
||||
_, err = io.ReadFull(br.r, buf[:])
|
||||
@ -117,8 +117,14 @@ func (br* ByteReader) ReadIp4() (net.IP, error) {
|
||||
return net.IP(buf[:]), nil
|
||||
}
|
||||
|
||||
func (br *ByteReader) ReadAllBytes(buf []byte) error {
|
||||
func (br *NetByteReader) ReadBytesFull(buf []byte) error {
|
||||
var err error
|
||||
_, err = io.ReadFull(br.r, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
func (br *NetByteReader) ReadBytesAtLeast(buf []byte, len int) error {
|
||||
var err error
|
||||
_, err = io.ReadAtLeast(br.r, buf, len)
|
||||
return err
|
||||
}
|
||||
|
225
opt.go
Normal file
225
opt.go
Normal file
@ -0,0 +1,225 @@
|
||||
package haza
|
||||
|
||||
import "encoding/binary"
|
||||
import "net"
|
||||
|
||||
type Dhcp4OptCode = uint8
|
||||
type Dhcp4MsgType = uint8
|
||||
|
||||
const (
|
||||
_ Dhcp4MsgType = iota
|
||||
|
||||
DHCP4_MSG_DISCOVER = 1
|
||||
DHCP4_MSG_OFFER = 2
|
||||
DHCP4_MSG_REQUEST = 3
|
||||
DHCP4_MSG_DECLINE = 4
|
||||
DHCP4_MSG_ACK = 5
|
||||
DHCP4_MSG_NAK = 6
|
||||
DHCP4_MSG_RELEASE = 7
|
||||
DHCP4_MSG_INFORM = 8
|
||||
|
||||
DHCP4_MSG_FORCE_RENEW = 9
|
||||
|
||||
DHCP4_MSG_LEASE_QUERY = 10
|
||||
DHCP4_MSG_LEASE_UNASSIGNED = 11
|
||||
DHCP4_MSG_LEASE_UNKNOWN = 12
|
||||
DHCP4_MSG_LEASE_ACTIVE = 13
|
||||
|
||||
DHCP4_MSG_BULK_LEASE_QUERY = 14
|
||||
DHCP4_MSG_LEASE_QUERY_DONE = 15
|
||||
DHCP4_MSG_ACTIVE_LEASE_QUERY = 16
|
||||
DHCP4_MSG_LEASE_QUERY_STATUS = 17
|
||||
DHCP4_MSG_TLS = 18
|
||||
)
|
||||
|
||||
const (
|
||||
DHCP4_OPT_PADDING Dhcp4OptCode = iota // 0
|
||||
DHCP4_OPT_SUBNET_MASK = 0x01
|
||||
DHCP4_OPT_TIME_OFFSET = 0x02
|
||||
DHCP4_OPT_ROUTER = 0x03
|
||||
DHCP4_OPT_TIME_SERVER = 0x04
|
||||
DHCP4_OPT_NAME_SERVER = 0x05
|
||||
DHCP4_OPT_DNS_SERVER = 0x06
|
||||
DHCP4_OPT_LOG_SERVER = 0x07
|
||||
DHCP4_OPT_QUOTE_SERVER = 0x08
|
||||
DHCP4_OPT_LPR_SERVER = 0x09
|
||||
|
||||
DHCP4_OPT_HOST_NAME = 0x0C
|
||||
DHCP4_OPT_VENDOR_SPECIFIC = 0x2B
|
||||
DHCP4_OPT_REQUESTED_IPADDR = 0x32
|
||||
DHCP4_OPT_LEASE_TIME = 0x33
|
||||
DHCP4_OPT_OVERLOAD = 0x34
|
||||
DHCP4_OPT_MSG_TYPE = 0x35
|
||||
DHCP4_OPT_SERVER_ID = 0x36
|
||||
DHCP4_OPT_PARAM_REQ_LIST = 0x37
|
||||
DHCP4_OPT_ERROR_TEXT = 0x38
|
||||
DHCP4_OPT_MAX_MSG_SIZE = 0x39
|
||||
DHCP4_OPT_RENEWAL_TIME = 0x3A // T1
|
||||
DHCP4_OPT_REBINDING_TIME = 0x3B // T2
|
||||
DHCP4_OPT_CLIENT_ID = 0x3D
|
||||
DHCP4_OPT_END = 0xFF
|
||||
)
|
||||
|
||||
const (
|
||||
DHCP4_OPT_VAL_UINT8 = 0
|
||||
)
|
||||
|
||||
type Dhcp4Opt interface {
|
||||
Code() Dhcp4OptCode
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
type Dhcp4OptBase struct {
|
||||
code Dhcp4OptCode
|
||||
}
|
||||
|
||||
type Dhcp4OptIp4Addr struct {
|
||||
Dhcp4OptBase
|
||||
value net.IP
|
||||
}
|
||||
|
||||
type Dhcp4OptIp4Addrs struct {
|
||||
Dhcp4OptBase
|
||||
value []net.IP
|
||||
}
|
||||
|
||||
type Dhcp4OptString struct {
|
||||
Dhcp4OptBase
|
||||
value string
|
||||
}
|
||||
|
||||
type Dhcp4OptBytes struct {
|
||||
Dhcp4OptBase
|
||||
value []byte
|
||||
}
|
||||
|
||||
type Dhcp4OptUint32 struct {
|
||||
Dhcp4OptBase
|
||||
value uint32
|
||||
}
|
||||
|
||||
type Dhcp4OptUint16 struct {
|
||||
Dhcp4OptBase
|
||||
value uint16
|
||||
}
|
||||
|
||||
type Dhcp4OptUint8 struct {
|
||||
Dhcp4OptBase
|
||||
value uint8
|
||||
}
|
||||
|
||||
func (opt *Dhcp4OptBase) Code() Dhcp4OptCode {
|
||||
return opt.code
|
||||
}
|
||||
|
||||
func (opt *Dhcp4OptIp4Addr) Bytes() []byte {
|
||||
// net.IP itself is []byte
|
||||
var buf []byte
|
||||
buf = opt.value.To4()
|
||||
if buf == nil { return []byte{} }
|
||||
return buf
|
||||
}
|
||||
|
||||
func (opt *Dhcp4OptIp4Addrs) Bytes() []byte {
|
||||
var buf []byte
|
||||
var v net.IP
|
||||
var v4 []byte
|
||||
var count int
|
||||
|
||||
count = 0
|
||||
for _, ip := range opt.value {
|
||||
if ip.To4() != nil { count++ }
|
||||
}
|
||||
|
||||
buf = make([]byte, 0, count * net.IPv4len)
|
||||
for _, v = range opt.value {
|
||||
v4 = v.To4()
|
||||
if v4 == nil { continue }
|
||||
buf = append(buf, v4...)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func (opt *Dhcp4OptString) Bytes() []byte {
|
||||
return []byte(opt.value)
|
||||
}
|
||||
|
||||
func (opt *Dhcp4OptBytes) Bytes() []byte {
|
||||
return opt.value
|
||||
}
|
||||
|
||||
func (opt *Dhcp4OptUint32) Bytes() []byte {
|
||||
var buf [4]byte
|
||||
binary.BigEndian.PutUint32(buf[:], opt.value)
|
||||
return buf[:]
|
||||
}
|
||||
|
||||
func (opt *Dhcp4OptUint16) Bytes() []byte {
|
||||
var buf [2]byte
|
||||
binary.BigEndian.PutUint16(buf[:], opt.value)
|
||||
return buf[:]
|
||||
}
|
||||
|
||||
func (opt *Dhcp4OptUint8) Bytes() []byte {
|
||||
return []byte{opt.value}
|
||||
}
|
||||
|
||||
func Dhcp4OptMsgType(v uint8) Dhcp4Opt {
|
||||
return &Dhcp4OptUint8{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_MSG_TYPE}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptSubnetMask(v net.IP) Dhcp4Opt {
|
||||
return &Dhcp4OptIp4Addr{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_SUBNET_MASK}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptRouter(v net.IP) Dhcp4Opt {
|
||||
return &Dhcp4OptIp4Addr{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_ROUTER}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptTimeServers(v []net.IP) Dhcp4Opt {
|
||||
return &Dhcp4OptIp4Addrs{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_TIME_SERVER}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptDnsServers(v []net.IP) Dhcp4Opt {
|
||||
return &Dhcp4OptIp4Addrs{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_DNS_SERVER}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptHostName(v string) Dhcp4Opt {
|
||||
return &Dhcp4OptString{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_DNS_SERVER}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptReqIpaddr(v net.IP) Dhcp4Opt {
|
||||
return &Dhcp4OptIp4Addr{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_REQUESTED_IPADDR}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptLeaseTime(v uint32) Dhcp4Opt {
|
||||
return &Dhcp4OptUint32{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_LEASE_TIME}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptServerId(v net.IP) Dhcp4Opt {
|
||||
return &Dhcp4OptIp4Addr{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_SERVER_ID}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptParamReqList(v []Dhcp4OptCode) Dhcp4Opt {
|
||||
return &Dhcp4OptBytes{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_PARAM_REQ_LIST}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptErrorText(v string) Dhcp4Opt {
|
||||
return &Dhcp4OptString{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_ERROR_TEXT}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptMaxMsgSize(v uint16) Dhcp4Opt {
|
||||
return &Dhcp4OptUint16{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_MAX_MSG_SIZE}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptRenewalTime(v uint32) Dhcp4Opt {
|
||||
return &Dhcp4OptUint32{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_RENEWAL_TIME}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptRebindingTime(v uint32) Dhcp4Opt {
|
||||
return &Dhcp4OptUint32{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_REBINDING_TIME}, value: v}
|
||||
}
|
||||
|
||||
func Dhcp4OptClientId(v string) Dhcp4Opt {
|
||||
return &Dhcp4OptString{Dhcp4OptBase: Dhcp4OptBase{code: DHCP4_OPT_CLIENT_ID}, value: v}
|
||||
}
|
198
pkt.go
198
pkt.go
@ -1,10 +1,12 @@
|
||||
package haza
|
||||
|
||||
import "errors"
|
||||
import "fmt"
|
||||
import "io"
|
||||
import "net"
|
||||
|
||||
type Dhcp4Op = uint8
|
||||
type Dhcp4Htype = uint8
|
||||
type Dhcp4Msg = uint8
|
||||
|
||||
const (
|
||||
_ Dhcp4Op = iota
|
||||
@ -26,32 +28,6 @@ const (
|
||||
DHCP4_HTYPE_PUREIP = 35
|
||||
)
|
||||
|
||||
const (
|
||||
_ Dhcp4Msg = iota
|
||||
|
||||
DHCP4_MSG_DISCOVER = 1
|
||||
DHCP4_MSG_OFFER = 2
|
||||
DHCP4_MSG_REQUEST = 3
|
||||
DHCP4_MSG_DECLINE = 4
|
||||
DHCP4_MSG_ACK = 5
|
||||
DHCP4_MSG_NAK = 6
|
||||
DHCP4_MSG_RELEASE = 7
|
||||
DHCP4_MSG_INFORM = 8
|
||||
|
||||
DHCP4_MSG_FORCE_RENEW = 9
|
||||
|
||||
DHCP4_MSG_LEASE_QUERY = 10
|
||||
DHCP4_MSG_LEASE_UNASSIGNED = 11
|
||||
DHCP4_MSG_LEASE_UNKNOWN = 12
|
||||
DHCP4_MSG_LEASE_ACTIVE = 13
|
||||
|
||||
DHCP4_MSG_BULK_LEASE_QUERY = 14
|
||||
DHCP4_MSG_LEASE_QUERY_DONE = 15
|
||||
DHCP4_MSG_ACTIVE_LEASE_QUERY = 16
|
||||
DHCP4_MSG_LEASE_QUERY_STATUS = 17
|
||||
DHCP4_MSG_TLS = 18
|
||||
)
|
||||
|
||||
type Dhcp4Pkt struct {
|
||||
Op Dhcp4Op
|
||||
Htype Dhcp4Htype
|
||||
@ -74,70 +50,168 @@ type Dhcp4Pkt struct {
|
||||
// options are placed after the header.
|
||||
// the first four bytes of the options compose a magic cookie
|
||||
// 0x63 0x82 0x53 0x63
|
||||
|
||||
Options map[Dhcp4OptCode][]byte
|
||||
|
||||
// internal fields
|
||||
msg_type Dhcp4MsgType
|
||||
}
|
||||
|
||||
var dhcp4_magic_cookie [4]byte = [4]byte{ 0x63, 0x82, 0x53, 0x63 }
|
||||
|
||||
func NewDhcp4Pkt(msg_type Dhcp4MsgType) *Dhcp4Pkt {
|
||||
var pkt *Dhcp4Pkt
|
||||
var opt Dhcp4Opt
|
||||
|
||||
pkt = &Dhcp4Pkt{
|
||||
Op: DHCP4_OP_BOOTREQUEST, // TODO: choose between request and reply based on the msg type..
|
||||
Htype: DHCP4_HTYPE_ETHER,
|
||||
Hlen: 6,
|
||||
Xid: 0, // TODO: generate it?
|
||||
|
||||
Ciaddr: net.IPv4zero,
|
||||
Yiaddr: net.IPv4zero,
|
||||
Siaddr: net.IPv4zero,
|
||||
Gwaddr: net.IPv4zero,
|
||||
|
||||
//Chaddr:
|
||||
//Sname:
|
||||
//File:
|
||||
|
||||
|
||||
// fill the internal fields
|
||||
msg_type: msg_type,
|
||||
}
|
||||
|
||||
// add the message type option
|
||||
opt = Dhcp4OptMsgType(msg_type)
|
||||
pkt.Options[opt.Code()] = opt.Bytes()
|
||||
|
||||
return pkt
|
||||
}
|
||||
|
||||
func (pkt *Dhcp4Pkt) AddOption(opt Dhcp4Opt) {
|
||||
pkt.Options[opt.Code()] = opt.Bytes();
|
||||
}
|
||||
|
||||
func (pkt *Dhcp4Pkt) Decode(b []byte) error {
|
||||
// fill the packet with data from the bytes
|
||||
var r *ByteReader
|
||||
var nbr *NetByteReader
|
||||
var u8 byte
|
||||
var u16 uint16
|
||||
var u32 uint32
|
||||
var p Dhcp4Pkt
|
||||
var cookie [4]byte
|
||||
var ov []byte
|
||||
var ok bool
|
||||
var err error
|
||||
|
||||
r = NewByteReader(b)
|
||||
nbr = NewNetByteReader(b)
|
||||
|
||||
u8, err = r.ReadByte()
|
||||
u8, err = nbr.ReadByte()
|
||||
if err != nil { return err }
|
||||
p.Op = Dhcp4Op(u8)
|
||||
|
||||
u8, err = r.ReadByte()
|
||||
u8, err = nbr.ReadByte()
|
||||
if err != nil { return err }
|
||||
p.Htype = Dhcp4Htype(u8)
|
||||
|
||||
u8, err = r.ReadByte()
|
||||
p.Hlen, err = nbr.ReadByte()
|
||||
if err != nil { return err }
|
||||
p.Hlen = u8
|
||||
if p.Hlen > 16 { return fmt.Errorf("invalid hlen %d", p.Hlen) }
|
||||
|
||||
u8, err = r.ReadByte()
|
||||
if err != nil { return err }
|
||||
p.Hops = u8
|
||||
|
||||
u32, err = r.ReadUint32()
|
||||
if err != nil { return err }
|
||||
p.Xid = u32
|
||||
|
||||
u16, err = r.ReadUint16()
|
||||
if err != nil { return err }
|
||||
p.Secs = u16
|
||||
|
||||
u16, err = r.ReadUint16()
|
||||
if err != nil { return err }
|
||||
p.Flags = u16
|
||||
|
||||
p.Ciaddr, err = r.ReadIp4()
|
||||
p.Hops, err = nbr.ReadByte()
|
||||
if err != nil { return err }
|
||||
|
||||
p.Yiaddr, err = r.ReadIp4()
|
||||
p.Xid, err = nbr.ReadUint32()
|
||||
if err != nil { return err }
|
||||
|
||||
p.Siaddr, err = r.ReadIp4()
|
||||
p.Secs, err = nbr.ReadUint16()
|
||||
if err != nil { return err }
|
||||
|
||||
p.Gwaddr, err = r.ReadIp4()
|
||||
p.Flags, err = nbr.ReadUint16()
|
||||
if err != nil { return err }
|
||||
|
||||
err = r.ReadAllBytes(p.Chaddr[:])
|
||||
p.Ciaddr, err = nbr.ReadIp4()
|
||||
if err != nil { return err }
|
||||
|
||||
err = r.ReadAllBytes(p.Sname[:])
|
||||
p.Yiaddr, err = nbr.ReadIp4()
|
||||
if err != nil { return err }
|
||||
|
||||
err = r.ReadAllBytes(p.File[:])
|
||||
p.Siaddr, err = nbr.ReadIp4()
|
||||
if err != nil { return err }
|
||||
|
||||
// magic
|
||||
// options..
|
||||
p.Gwaddr, err = nbr.ReadIp4()
|
||||
if err != nil { return err }
|
||||
|
||||
err = nbr.ReadBytesFull(p.Chaddr[:])
|
||||
if err != nil { return err }
|
||||
|
||||
err = nbr.ReadBytesFull(p.Sname[:])
|
||||
if err != nil { return err }
|
||||
|
||||
err = nbr.ReadBytesFull(p.File[:])
|
||||
if err != nil { return err }
|
||||
|
||||
err = nbr.ReadBytesFull(cookie[:])
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
// TODO: no options
|
||||
}
|
||||
return err
|
||||
}
|
||||
if cookie != dhcp4_magic_cookie {
|
||||
return fmt.Errorf("invalid magic cookie %v", cookie)
|
||||
}
|
||||
|
||||
// load options
|
||||
p.Options = make(map[Dhcp4OptCode][]byte)
|
||||
for {
|
||||
var oc uint8
|
||||
var ol uint8
|
||||
var optval [255]byte
|
||||
|
||||
oc, err = nbr.ReadByte() // option code
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) { break }
|
||||
return err
|
||||
}
|
||||
|
||||
if oc == DHCP4_OPT_PADDING { continue }
|
||||
if oc == DHCP4_OPT_END { break }
|
||||
|
||||
ol, err = nbr.ReadByte() // option length
|
||||
if err != nil { return err }
|
||||
|
||||
err = nbr.ReadBytesAtLeast(optval[:], int(ol))
|
||||
if err != nil { return err }
|
||||
|
||||
// RFC 3396 mandates that when multiple occurrences of a concatenation-requiring
|
||||
// option appear in a DHCPv4 packet, their data MUST be concatenated prior to
|
||||
// processing. For non-concatenation-requiring (e.g. fixed-length) options, concatenation
|
||||
// is not defined. but let's not make an exception and let the processor check
|
||||
// validity.
|
||||
p.Options[oc] = append(p.Options[oc], optval[:ol]...)
|
||||
}
|
||||
|
||||
//for oc, ov = range p.Optons {
|
||||
// ot = oc_to_type(oc)
|
||||
// switch (ot) {
|
||||
// case OT_UINT8:
|
||||
// case OT_UINT16:
|
||||
// case OT_UINT18:
|
||||
// case OT_UINT32:
|
||||
// case OT_IP4ADDR:
|
||||
// case OT_IP46DDR:
|
||||
// case OT_STRING:
|
||||
// default:
|
||||
// leave it as is
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
ov, ok = p.Options[DHCP4_OPT_MSG_TYPE]
|
||||
if !ok { return fmt.Errorf("no message type") }
|
||||
if len(ov) != 1 { return fmt.Errorf("invalid message type option") }
|
||||
p.msg_type = ov[0]
|
||||
|
||||
*pkt = p
|
||||
return nil
|
||||
@ -146,3 +220,7 @@ func (pkt *Dhcp4Pkt) Decode(b []byte) error {
|
||||
func (pkt *Dhcp4Pkt) Encode() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pkt *Dhcp4Pkt) MsgType() Dhcp4MsgType {
|
||||
return pkt.msg_type
|
||||
}
|
||||
|
101
server.go
101
server.go
@ -31,6 +31,7 @@ type DhcpServer struct {
|
||||
p int // epoll
|
||||
efd int // eventfd
|
||||
|
||||
pkt_chan chan[]byte
|
||||
|
||||
log Logger
|
||||
}
|
||||
@ -104,6 +105,7 @@ func NewDhcpServer(ctx context.Context, name string, logger Logger) (*DhcpServer
|
||||
s.p = p
|
||||
s.conns = make(map[string]DhcpConn, 0)
|
||||
s.conns_by_fd = make(map[int]DhcpConn, 0)
|
||||
s.pkt_chan = make(chan[]byte, 256)
|
||||
|
||||
runtime.SetFinalizer(s, finalize_dhcp_server)
|
||||
return s, nil
|
||||
@ -154,9 +156,9 @@ func (s *DhcpServer) RunTask(wg *sync.WaitGroup) {
|
||||
go s.run_handlers(&l_wg)
|
||||
}
|
||||
*/
|
||||
fmt.Printf ("beginning of recv loop\n")
|
||||
s.log.Write("", LOG_INFO, "Receiver loop started")
|
||||
s.run_recv_loop()
|
||||
fmt.Printf ("end of recv loop\n")
|
||||
s.log.Write("", LOG_INFO, "Receiver loop ended")
|
||||
|
||||
// l_wg.Wait()
|
||||
finalize_dhcp_server(s)
|
||||
@ -168,6 +170,7 @@ func (s *DhcpServer) ReqStop() {
|
||||
// eventfd needs an 8-byte integer.
|
||||
v = 1
|
||||
unix.Write(s.efd, (*[8]byte)(unsafe.Pointer(&v))[:])
|
||||
s.CtxCancel()
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,13 +259,92 @@ func get_offsets(frame []byte) (int, int, int, int, int, error) {
|
||||
return eth_off, ip_off, udp_off, dhcp_off, dhcp_end, nil
|
||||
}
|
||||
|
||||
func (s *DhcpServer) dhcp4_discover(pkt *Dhcp4Pkt) {
|
||||
fmt.Printf("discover...\n")
|
||||
|
||||
|
||||
/*
|
||||
ans = NewDhcp4Pkt(
|
||||
Dhcp4OptMsgType(HDCP4_MSG_OFFER),
|
||||
Dhcp4Ciaddr("192.168.2.3")
|
||||
)
|
||||
*/
|
||||
|
||||
//Send(ans)
|
||||
}
|
||||
|
||||
func (s *DhcpServer) dhcp4_request(pkt *Dhcp4Pkt) {
|
||||
fmt.Printf("request...\n")
|
||||
}
|
||||
|
||||
func (s *DhcpServer) dhcp4_release(pkt *Dhcp4Pkt) {
|
||||
fmt.Printf("release...\n")
|
||||
}
|
||||
|
||||
func (s *DhcpServer) dhcp4_inform(pkt *Dhcp4Pkt) {
|
||||
fmt.Printf("inform...\n")
|
||||
}
|
||||
|
||||
func (s *DhcpServer) dhcp4_lease_query(pkt *Dhcp4Pkt) {
|
||||
fmt.Printf("lease query...\n")
|
||||
}
|
||||
// TODO:bulk lease query, etc
|
||||
|
||||
func (s *DhcpServer) dhcp4_packet_proc(wg *sync.WaitGroup, id int) {
|
||||
var buf []byte
|
||||
var err error
|
||||
|
||||
defer wg.Done()
|
||||
|
||||
s.log.Write("", LOG_INFO, "dhcp4 packet processor(%d) started", id)
|
||||
|
||||
proc_loop:
|
||||
for {
|
||||
select {
|
||||
case <- s.Ctx.Done():
|
||||
break proc_loop
|
||||
|
||||
case buf = <- s.pkt_chan:
|
||||
var pkt Dhcp4Pkt
|
||||
//TODO: ethernet part???
|
||||
err = pkt.Decode(buf)
|
||||
if err != nil { continue }
|
||||
|
||||
switch pkt.MsgType() {
|
||||
case DHCP4_MSG_DISCOVER:
|
||||
s.dhcp4_discover(&pkt)
|
||||
case DHCP4_MSG_REQUEST:
|
||||
s.dhcp4_request(&pkt)
|
||||
case DHCP4_MSG_RELEASE:
|
||||
s.dhcp4_release(&pkt)
|
||||
case DHCP4_MSG_INFORM:
|
||||
s.dhcp4_inform(&pkt)
|
||||
case DHCP4_MSG_LEASE_QUERY:
|
||||
s.dhcp4_lease_query(&pkt)
|
||||
default:
|
||||
// do nothing. ignore other types?
|
||||
// TODO: logging?
|
||||
}
|
||||
//fmt.Printf("[%d] PKT: %+v\n", id, pkt)
|
||||
}
|
||||
}
|
||||
|
||||
s.log.Write("", LOG_INFO, "dhcp4 packet processor(%d) ended", id)
|
||||
}
|
||||
|
||||
func (s *DhcpServer) run_recv_loop() error {
|
||||
var buf [1500]byte
|
||||
var nevts int
|
||||
var i int
|
||||
var evts [128]unix.EpollEvent
|
||||
var l_wg sync.WaitGroup
|
||||
var err error
|
||||
|
||||
for i = 0; i < 10; i++ { // how many go rootines would be the best?
|
||||
l_wg.Add(1)
|
||||
go s.dhcp4_packet_proc(&l_wg, i)
|
||||
}
|
||||
|
||||
epoll_loop:
|
||||
for {
|
||||
nevts, err = unix.EpollWait(s.p, evts[:], -1)
|
||||
@ -297,15 +379,11 @@ epoll_loop:
|
||||
if err != nil {
|
||||
fmt.Printf ("PACKET -> %s\n", err.Error())
|
||||
} else {
|
||||
//fmt.Printf (">>%d [%s]<<\n", epos - spos, string(buf[spos: epos]))
|
||||
if string(buf[spos:epos]) == "quit\n" {
|
||||
break epoll_loop
|
||||
}
|
||||
|
||||
|
||||
var pkt Dhcp4Pkt
|
||||
pkt.Decode(buf[spos:epos])
|
||||
fmt.Printf("%+v\n", pkt)
|
||||
//var pkt Dhcp4Pkt
|
||||
//TODO: ethernet part???
|
||||
//pkt.Decode(buf[spos:epos])
|
||||
//fmt.Printf("%+v\n", pkt)
|
||||
s.pkt_chan <- buf[spos:epos]
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,5 +397,6 @@ epoll_loop:
|
||||
}
|
||||
|
||||
// if there are subtasks wait here for termination and close the dockets
|
||||
l_wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user