mirror of
https://github.com/danderson/netboot.git
synced 2025-08-10 16:47:11 +02:00
129 lines
2.7 KiB
Go
129 lines
2.7 KiB
Go
package dhcp6
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"time"
|
|
"golang.org/x/net/ipv6"
|
|
"fmt"
|
|
)
|
|
|
|
type conn interface {
|
|
io.Closer
|
|
Recv([]byte) (b []byte, addr *net.UDPAddr, ifidx int, err error)
|
|
Send(b []byte, addr *net.UDPAddr, ifidx int) error
|
|
SetReadDeadline(t time.Time) error
|
|
SetWriteDeadline(t time.Time) error
|
|
}
|
|
|
|
type Conn struct {
|
|
conn *ipv6.PacketConn
|
|
group net.IP
|
|
ifi *net.Interface
|
|
listenAddress string
|
|
listenPort string
|
|
}
|
|
|
|
func NewConn(addr, port string) (*Conn, error) {
|
|
ifi, err := InterfaceByAddress(addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
group := net.ParseIP("ff02::1:2")
|
|
c, err := net.ListenPacket("udp6", "[::]:" + port)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pc := ipv6.NewPacketConn(c)
|
|
if err := pc.JoinGroup(ifi, &net.UDPAddr{IP: group}); err != nil {
|
|
pc.Close()
|
|
return nil, err
|
|
}
|
|
|
|
if err := pc.SetControlMessage(ipv6.FlagSrc | ipv6.FlagDst, true); err != nil {
|
|
pc.Close()
|
|
return nil, err
|
|
}
|
|
|
|
return &Conn{
|
|
conn: pc,
|
|
group: group,
|
|
ifi: ifi,
|
|
listenAddress: addr,
|
|
listenPort: port,
|
|
}, nil
|
|
}
|
|
|
|
func (c *Conn) Close() error {
|
|
return c.conn.Close()
|
|
}
|
|
|
|
func InterfaceByAddress(ifAddr string) (*net.Interface, error) {
|
|
allIfis, err := net.Interfaces()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Error getting network interface information: %s", err)
|
|
}
|
|
for _, ifi := range allIfis {
|
|
addrs, err := ifi.Addrs()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Error getting network interface address information: %s", err)
|
|
}
|
|
for _, addr := range addrs {
|
|
if addrToIP(addr).String() == ifAddr {
|
|
return &ifi, nil
|
|
}
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("Couldn't find an interface with address %s", ifAddr)
|
|
}
|
|
|
|
func addrToIP(a net.Addr) net.IP {
|
|
var ip net.IP
|
|
switch v := a.(type) {
|
|
case *net.IPAddr:
|
|
ip = v.IP
|
|
case *net.IPNet:
|
|
ip = v.IP
|
|
}
|
|
|
|
return ip
|
|
}
|
|
|
|
func (c *Conn) RecvDHCP() (*Packet, net.IP, error) {
|
|
b := make([]byte, 1500)
|
|
for {
|
|
n, rcm, _, err := c.conn.ReadFrom(b)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if c.ifi.Index != 0 && rcm.IfIndex != c.ifi.Index {
|
|
continue
|
|
}
|
|
if !rcm.Dst.IsMulticast() || !rcm.Dst.Equal(c.group) {
|
|
continue // unknown group, discard
|
|
}
|
|
pkt, err := MakePacket(b, n)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return pkt, rcm.Src, nil
|
|
}
|
|
}
|
|
|
|
func (c *Conn) SendDHCP(dst net.IP, p []byte) error {
|
|
dstAddr, err := net.ResolveUDPAddr("udp6", fmt.Sprintf("[%s]:%s", dst.String() + "%en0", "546"))
|
|
if err != nil {
|
|
return fmt.Errorf("Error resolving ipv6 address %s: %s", dst.String(), err)
|
|
}
|
|
_, err = c.conn.WriteTo(p, nil, dstAddr)
|
|
if err != nil {
|
|
return fmt.Errorf("Error sending a reply to %s: %s", dst.String(), err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Conn) SourceHardwareAddress() net.HardwareAddr {
|
|
return c.ifi.HardwareAddr
|
|
} |