zoukankan      html  css  js  c++  java
  • golang DHCPv4/v6 demo

    server端代码如下:

    package main
    
    import (
            "errors"
            "fmt"
            "github.com/insomniacslk/dhcp/dhcpv4"
            "github.com/insomniacslk/dhcp/dhcpv4/server4"
            "github.com/insomniacslk/dhcp/dhcpv6"
            "github.com/insomniacslk/dhcp/dhcpv6/server6"
            "github.com/insomniacslk/dhcp/iana"
            "github.com/mdlayher/ndp"
            "golang.org/x/net/ipv6"
            "log"
            "net"
            "time"
    )
    
    type dhcpV4 struct{}
    type dhcpV6 struct{}
    
    func (v4 *dhcpV4) sendOffer(conn net.PacketConn, m *dhcpv4.DHCPv4, peer net.Addr) {
            requestIpAddr := m.RequestedIPAddress()
            if requestIpAddr == nil {
                    requestIpAddr = net.IP{192, 168, 0, 100}
            }
    
            offer, err := dhcpv4.New(
                    dhcpv4.WithMessageType(dhcpv4.MessageTypeOffer),
                    dhcpv4.WithServerIP(net.IP{192, 168, 0, 1}),
                    dhcpv4.WithYourIP(requestIpAddr),
                    dhcpv4.WithHwAddr(m.ClientHWAddr),
            )
            if err != nil {
                    log.Fatal(err)
                    return
            }
            offer.OpCode = dhcpv4.OpcodeBootReply
            offer.ServerHostName = "test"
            offer.TransactionID = m.TransactionID
    
            offer.UpdateOption(dhcpv4.OptSubnetMask(net.IPMask{255, 255, 255, 0}))
            offer.UpdateOption(dhcpv4.OptRouter(net.IPv4(192, 168, 0, 1)))
            offer.UpdateOption(dhcpv4.OptServerIdentifier(net.IP{192, 168, 0, 2}))
    
            if _, err := conn.WriteTo(offer.ToBytes(), peer); err != nil {
                    log.Fatal(err)
            }
            log.Print(offer.Summary())
    }
    
    func (v4 *dhcpV4) sendReplyFromRequest(conn net.PacketConn, m *dhcpv4.DHCPv4, peer net.Addr) {
            requestIpAddr := m.RequestedIPAddress()
            if requestIpAddr == nil {
                    requestIpAddr = net.IP{192, 168, 0, 100}
            }
    
            ack, err := dhcpv4.New(
                    dhcpv4.WithMessageType(dhcpv4.MessageTypeAck),
                    dhcpv4.WithServerIP(net.IP{192, 168, 0, 1}),
                    dhcpv4.WithYourIP(requestIpAddr),
                    dhcpv4.WithHwAddr(m.ClientHWAddr),
            )
            if err != nil {
                    log.Fatal(err)
                    return
            }
    
            ack.OpCode = dhcpv4.OpcodeBootReply
            ack.ServerHostName = "test"
            ack.TransactionID = m.TransactionID
    
            ack.UpdateOption(dhcpv4.OptSubnetMask(net.IPMask{255, 255, 255, 0}))
            ack.UpdateOption(dhcpv4.OptRouter(net.IPv4(192, 168, 0, 1)))
            ack.UpdateOption(dhcpv4.OptServerIdentifier(net.IP{192, 168, 0, 2}))
            ack.UpdateOption(dhcpv4.OptDNS(net.IPv4(8, 8, 8, 8), net.IPv4(114, 114, 114, 114)))
            ack.UpdateOption(dhcpv4.OptIPAddressLeaseTime(43200 * time.Second))
    
            // static route
            _, ipNet1, err := net.ParseCIDR("1.1.1.0/24")
            if err != nil {
                    panic(err)
                    return
            }
            route1 := &dhcpv4.Route{
                    Dest:   ipNet1,
                    Router: net.IP{192, 168, 0, 220},
            }
    
            _, ipNet2, err := net.ParseCIDR("2.2.2.0/24")
            if err != nil {
                    panic(err)
                    return
            }
            route2 := &dhcpv4.Route{
                    Dest:   ipNet2,
                    Router: net.IP{192, 168, 0, 221},
            }
    
            _, ipNet3, err := net.ParseCIDR("0.0.0.0/0")
            if err != nil {
                    panic(err)
                    return
            }
            route3 := &dhcpv4.Route{
                    Dest:   ipNet3,
                    Router: net.IP{192, 168, 0, 1},
            }
            ack.UpdateOption(dhcpv4.OptClasslessStaticRoute(route1, route2, route3))
    
            if _, err := conn.WriteTo(ack.ToBytes(), peer); err != nil {
                    log.Fatal(err)
            }
            log.Print(ack.Summary())
    }
    
    func (v4 *dhcpV4) sendReplyFromRelease(conn net.PacketConn, m *dhcpv4.DHCPv4, peer net.Addr) {
    
    }
    
    func (v6 *dhcpV6) sendAdvertise(conn net.PacketConn, m dhcpv6.DHCPv6, peer net.Addr) {
            message, err := m.GetInnerMessage()
            if err != nil {
                    log.Fatal(err)
                    return
            }
    
            iface, err := net.InterfaceByName(IFNAME)
            if err != nil {
                    log.Fatal(err)
            }
            sid := dhcpv6.Duid{
                    Type:          dhcpv6.DUID_LLT,
                    HwType:        iana.HWTypeEthernet,
                    Time:          dhcpv6.GetTime(),
                    LinkLayerAddr: iface.HardwareAddr,
            }
    
            adv, err := dhcpv6.NewAdvertiseFromSolicit(message, dhcpv6.WithServerID(sid))
            if err != nil {
                    log.Fatal(err)
            }
    
            // add Elapsed Time
            adv.AddOption(dhcpv6.OptElapsedTime(0))
    
            // add IA_NA
            {
                    addr := &dhcpv6.OptIAAddress{
                            IPv6Addr:          net.ParseIP("4000::100"),
                            PreferredLifetime: 0x1C20 * time.Second,
                            ValidLifetime:     0x2A30 * time.Second,
                    }
    
                    //addrPrefix := &dhcpv6.OptIAPrefix{
                    //      Prefix: &net.IPNet{
                    //              Mask: net.CIDRMask(64, 128),
                    //              IP:   net.ParseIP("4000::1"),
                    //      },
                    //      PreferredLifetime: 0x1C20 * time.Second,
                    //      ValidLifetime:     0x2A30 * time.Second,
                    //}
    
                    iana := message.Options.OneIANA()
                    iana.T1 = time.Duration(3600) * time.Second
                    iana.T2 = time.Duration(5400) * time.Second
    
                    iana.Options.Add(addr)
                    //iana.Options.Add(addrPrefix)
    
                    adv.AddOption(iana)
            }
    
            // add status code
            {
                    opt := dhcpv6.OptStatusCode{
                            StatusCode:    iana.StatusSuccess,
                            StatusMessage: "success",
                    }
                    adv.AddOption(&opt)
            }
    
            // add dns opt
            {
                    ns1 := net.ParseIP("1000:2000:1000::1")
                    ns2 := net.ParseIP("1000:2000:1000::2")
                    nameservers := []net.IP{ns1, ns2}
                    opt := dhcpv6.OptDNS(nameservers...)
                    adv.AddOption(opt)
            }
    
            // add domain search list
            {
            }
    
            if _, err := conn.WriteTo(adv.ToBytes(), peer); err != nil {
                    log.Fatal(err)
            }
            log.Print(adv.Summary())
    }
    
    func (v6 *dhcpV6) sendReplyFromRequest(conn net.PacketConn, request dhcpv6.DHCPv6, peer net.Addr) {
            message, err := request.GetInnerMessage()
            if err != nil {
                    log.Fatal(err)
            }
    
            // add Server ID
            iface, err := net.InterfaceByName(IFNAME)
            if err != nil {
                    log.Fatal(err)
            }
            sid := dhcpv6.Duid{
                    Type:          dhcpv6.DUID_LLT,
                    HwType:        iana.HWTypeEthernet,
                    Time:          dhcpv6.GetTime(),
                    LinkLayerAddr: iface.HardwareAddr,
            }
    
            rep, err := dhcpv6.NewReplyFromMessage(message, dhcpv6.WithServerID(sid))
            if err != nil {
                    log.Fatal(err)
            }
    
            // add IA_NA
            {
                    iana := message.Options.OneIANA()
                    iana.T1 = time.Duration(3600) * time.Second
                    iana.T2 = time.Duration(5400) * time.Second
                    rep.AddOption(iana)
            }
    
            // add status code
            {
                    opt := dhcpv6.OptStatusCode{
                            StatusCode:    iana.StatusSuccess,
                            StatusMessage: "success",
                    }
                    rep.AddOption(&opt)
            }
    
            // dns
            {
                    ns1 := net.ParseIP("1000:2000:1000::1")
                    ns2 := net.ParseIP("1000:2000:1000::2")
                    nameservers := []net.IP{ns1, ns2}
                    opt := dhcpv6.OptDNS(nameservers...)
                    rep.AddOption(opt)
            }
    
            // IAPD
            //oAddr := dhcpv6.OptIAPrefix{
            //      Prefix: &net.IPNet{
            //              Mask: net.CIDRMask(64, 128),
            //              IP:   net.ParseIP("4000::100"),
            //      },
            //      PreferredLifetime: 0x1C20 * time.Second,
            //      ValidLifetime:     0x2A30 * time.Second,
            //}
            //opt := dhcpv6.OptIAPD{
            //      IaId:    [4]byte{175, 62, 198, 235},
            //      T1:      time.Duration(3600) * time.Second,
            //      T2:      time.Duration(5400) * time.Second,
            //      Options: dhcpv6.PDOptions{[]dhcpv6.Option{&oAddr}},
            //}
            //rep.AddOption(&opt)
    
            if _, err := conn.WriteTo(rep.ToBytes(), peer); err != nil {
                    log.Fatal(err)
            }
            log.Print(rep.Summary())
    }
    
    func (v6 *dhcpV6) sendReplyFromConfirm(conn net.PacketConn, confirm dhcpv6.DHCPv6, peer net.Addr) {
            message, err := confirm.GetInnerMessage()
            if err != nil {
                    log.Fatal(err)
            }
    
            // add Server ID
            iface, err := net.InterfaceByName(IFNAME)
            if err != nil {
                    log.Fatal(err)
            }
            sid := dhcpv6.Duid{
                    Type:          dhcpv6.DUID_LLT,
                    HwType:        iana.HWTypeEthernet,
                    Time:          dhcpv6.GetTime(),
                    LinkLayerAddr: iface.HardwareAddr,
            }
    
            rep, err := dhcpv6.NewReplyFromMessage(message, dhcpv6.WithServerID(sid))
            if err != nil {
                    log.Fatal(err)
            }
    
            // add IA_NA
            {
                    iana := message.Options.OneIANA()
                    iana.T1 = time.Duration(3600) * time.Second
                    iana.T2 = time.Duration(5400) * time.Second
                    rep.AddOption(iana)
            }
    
            // add status code
            {
                    opt := dhcpv6.OptStatusCode{
                            StatusCode:    iana.StatusSuccess,
                            StatusMessage: "success",
                    }
                    rep.AddOption(&opt)
            }
    
            // dns
            {
                    ns1 := net.ParseIP("1000:2000:1000::1")
                    ns2 := net.ParseIP("1000:2000:1000::2")
                    nameservers := []net.IP{ns1, ns2}
                    opt := dhcpv6.OptDNS(nameservers...)
                    rep.AddOption(opt)
            }
    
            if _, err := conn.WriteTo(rep.ToBytes(), peer); err != nil {
                    log.Fatal(err)
            }
            log.Print(rep.Summary())
    }
    
    func (v6 *dhcpV6) sendReplyFromRebind(conn net.PacketConn, rebind dhcpv6.DHCPv6, peer net.Addr) {
            message, err := rebind.GetInnerMessage()
            if err != nil {
                    log.Fatal(err)
            }
    
            // add Server ID
            iface, err := net.InterfaceByName(IFNAME)
            if err != nil {
                    log.Fatal(err)
            }
            sid := dhcpv6.Duid{
                    Type:          dhcpv6.DUID_LLT,
                    HwType:        iana.HWTypeEthernet,
                    Time:          dhcpv6.GetTime(),
                    LinkLayerAddr: iface.HardwareAddr,
            }
    
            rep, err := dhcpv6.NewReplyFromMessage(message, dhcpv6.WithServerID(sid))
            if err != nil {
                    log.Fatal(err)
            }
    
            // add IA_NA
            {
                    iana := message.Options.OneIANA()
                    iana.T1 = time.Duration(3600) * time.Second
                    iana.T2 = time.Duration(5400) * time.Second
                    rep.AddOption(iana)
            }
    
            // add status code
            {
                    opt := dhcpv6.OptStatusCode{
                            StatusCode:    iana.StatusSuccess,
                            StatusMessage: "success",
                    }
                    rep.AddOption(&opt)
            }
    
            // dns
            {
                    ns1 := net.ParseIP("1000:2000:1000::1")
                    ns2 := net.ParseIP("1000:2000:1000::2")
                    nameservers := []net.IP{ns1, ns2}
                    opt := dhcpv6.OptDNS(nameservers...)
                    rep.AddOption(opt)
            }
    
            if _, err := conn.WriteTo(rep.ToBytes(), peer); err != nil {
                    log.Fatal(err)
            }
            log.Print(rep.Summary())
    }
    
    func (v6 *dhcpV6) sendReplyFromRelease(conn net.PacketConn, release dhcpv6.DHCPv6, peer net.Addr) {
            message, err := release.GetInnerMessage()
            if err != nil {
                    log.Fatal(err)
            }
    
            // add Server ID
            iface, err := net.InterfaceByName(IFNAME)
            if err != nil {
                    log.Fatal(err)
            }
            sid := dhcpv6.Duid{
                    Type:          dhcpv6.DUID_LLT,
                    HwType:        iana.HWTypeEthernet,
                    Time:          dhcpv6.GetTime(),
                    LinkLayerAddr: iface.HardwareAddr,
            }
    
            rep, err := dhcpv6.NewReplyFromMessage(message, dhcpv6.WithServerID(sid))
            if err != nil {
                    log.Fatal(err)
            }
    
            // add status code
            opt := dhcpv6.OptStatusCode{
                    StatusCode:    iana.StatusSuccess,
                    StatusMessage: "success",
            }
            rep.AddOption(&opt)
    
            if _, err := conn.WriteTo(rep.ToBytes(), peer); err != nil {
                    log.Fatal(err)
            }
            log.Print(rep.Summary())
    }
    
    func handlerV4(conn net.PacketConn, peer net.Addr, m *dhcpv4.DHCPv4) {
            dhcpType := m.MessageType()
            log.Printf("type: %+v.", dhcpType)
            log.Print(m.Summary())
            v4 := dhcpV4{}
    
            switch dhcpType {
            case dhcpv4.MessageTypeDiscover:
                    v4.sendOffer(conn, m, peer)
            case dhcpv4.MessageTypeRequest:
                    v4.sendReplyFromRequest(conn, m, peer)
            case dhcpv4.MessageTypeInform:
            case dhcpv4.MessageTypeRelease:
                    v4.sendReplyFromRelease(conn, m, peer)
            }
    }
    
    func handlerV6(conn net.PacketConn, peer net.Addr, m dhcpv6.DHCPv6) {
            dhcpType := m.Type()
            log.Printf("type: %+v.", dhcpType)
            log.Print(m.Summary())
            v6 := dhcpV6{}
    
            switch dhcpType {
            case dhcpv6.MessageTypeSolicit:
                    v6.sendAdvertise(conn, m, peer)
            case dhcpv6.MessageTypeRequest:
                    v6.sendReplyFromRequest(conn, m, peer)
            case dhcpv6.MessageTypeConfirm:
                    v6.sendReplyFromConfirm(conn, m, peer)
            case dhcpv6.MessageTypeRebind:
                    v6.sendReplyFromRebind(conn, m, peer)
            case dhcpv6.MessageTypeRelease:
                    v6.sendReplyFromRelease(conn, m, peer)
            case dhcpv6.MessageTypeDecline:
            case dhcpv6.MessageTypeReconfigure:
            case dhcpv6.MessageTypeInformationRequest:
            case dhcpv6.MessageTypeRenew:
            case dhcpv6.MessageTypeRelayForward:
            }
    }
    
    func handleRouterSolicitation(c *ndp.Conn, msg ndp.Message, ifname string) {
            log.Printf("start handle icmpv6 packet, type is %+v.", msg.Type())
    
            // fetch source mac
            intf, err := net.InterfaceByName(ifname)
            if err != nil {
                    log.Fatal(err)
                    return
            }
            addr := intf.HardwareAddr
    
            raMsg := &ndp.RouterAdvertisement{
                    CurrentHopLimit:           64,
                    ManagedConfiguration:      true,
                    OtherConfiguration:        true,
                    RouterSelectionPreference: ndp.Medium,
                    RouterLifetime:            ndp.Infinity,
                    ReachableTime:             0,
                    RetransmitTimer:           0,
                    Options: []ndp.Option{
                            &ndp.LinkLayerAddress{
                                    Direction: ndp.Source,
                                    Addr:      addr,
                            },
                            ndp.NewMTU(1500),
                            &ndp.PrefixInformation{
                                    PrefixLength:                   96,
                                    OnLink:                         true,
                                    AutonomousAddressConfiguration: true,
                                    ValidLifetime:                  ndp.Infinity,
                                    PreferredLifetime:              ndp.Infinity,
                                    Prefix:                         net.ParseIP("4000::"),
                            },
                            &ndp.RouteInformation{
                                    PrefixLength:  0,
                                    Preference:    ndp.Medium,
                                    RouteLifetime: ndp.Infinity,
                                    Prefix:        net.IPv6zero,
                            },
                            &ndp.RouteInformation{
                                    PrefixLength:  64,
                                    Preference:    ndp.Medium,
                                    RouteLifetime: ndp.Infinity,
                                    Prefix:        net.ParseIP("6000::"),
                            },
                            &ndp.RouteInformation{
                                    PrefixLength:  128,
                                    Preference:    ndp.Medium,
                                    RouteLifetime: ndp.Infinity,
                                    Prefix:        net.ParseIP("8000::1"),
                            },
                    },
            }
    
            if err := c.WriteTo(raMsg, nil, net.IPv6linklocalallnodes); err != nil {
                    log.Printf("failed to send router advertisement: %v", err)
                    return
            }
    
            log.Printf("end of handle send route advertisement packet.")
    }
    
    func findInterface(name string) (*net.Interface, error) {
            if name != "" {
                    ifi, err := net.InterfaceByName(name)
                    if err != nil {
                            return nil, fmt.Errorf("could not find interface %q: %v", name, err)
                    }
    
                    return ifi, nil
            }
    
            ifis, err := net.Interfaces()
            if err != nil {
                    return nil, err
            }
    
            for _, ifi := range ifis {
                    // Is the interface up and not a loopback?
                    if ifi.Flags&net.FlagUp != 1 || ifi.Flags&net.FlagLoopback != 0 {
                            continue
                    }
    
                    // Does the interface have an IPv6 address assigned?
                    addrs, err := ifi.Addrs()
                    if err != nil {
                            return nil, err
                    }
    
                    for _, a := range addrs {
                            ipNet, ok := a.(*net.IPNet)
                            if !ok {
                                    continue
                            }
    
                            // Is this address an IPv6 address?
                            if ipNet.IP.To16() != nil && ipNet.IP.To4() == nil {
                                    return &ifi, nil
                            }
                    }
            }
    
            return nil, errors.New("could not find a usable IPv6-enabled interface")
    }
    
    func listenPacket(ifname string, addrFlag string) {
            ifi, err := findInterface(ifname)
            if err != nil {
                    log.Fatalf("failed to get interface: %v", err)
                    return
            }
    
            addr := ndp.Addr(addrFlag)
            c, _, err := ndp.Dial(ifi, addr)
            if err != nil {
                    log.Fatalf("failed to dial NDP connection: %v", err)
                    return
            }
            defer c.Close()
    
            if err := c.JoinGroup(net.IPv6linklocalallrouters); err != nil {
                    log.Fatal(err)
                    return
            }
            if err := c.JoinGroup(net.IPv6linklocalallnodes); err != nil {
                    log.Fatal(err)
                    return
            }
    
            for {
                    m, _, _, err := c.ReadFrom()
                    if err != nil {
                            log.Printf("ReadFrom failed: %v", err)
                            return
                    }
                    fmt.Println(m, m.Type())
    
                    msgType := m.Type()
                    switch msgType {
                    case ipv6.ICMPTypeRouterSolicitation:
                            go handleRouterSolicitation(c, m, ifname)
                    default:
                            continue
                    }
            }
    }
    
    var (
            IFNAME string = "ens38"
            DEVMAC string = "fe80::20c:29ff:fe10:dc1a"
    )
    
    func main() {
            log.Printf("dhcpv4 server start ... ...")
            laddrV4 := &net.UDPAddr{
                    IP:   net.ParseIP("0.0.0.0"),
                    Port: 67,
            }
            serverV4, err := server4.NewServer(IFNAME, laddrV4, handlerV4, server4.WithDebugLogger())
            if err != nil {
                    log.Fatal(err)
            }
            go serverV4.Serve()
    
            log.Printf("dhcpv6 server start ... ...")
            laddrV6 := &net.UDPAddr{
                    IP:   net.ParseIP("::"),
                    Port: 547,
            }
            serverV6, err := server6.NewServer(IFNAME, laddrV6, handlerV6, server6.WithDebugLogger())
            if err != nil {
                    log.Fatal(err)
            }
    
            go serverV6.Serve()
    
            listenPacket(IFNAME, DEVMAC)
    }
  • 相关阅读:
    [BZOJ1006]神奇的国度
    配置ubuntu18.04
    数据库的基本操作
    关于排序的算法——桶排序
    关于TCP/IP协议的记录
    laravel学习历程
    装箱问题
    01背包
    数字三角形
    统计单词的个数
  • 原文地址:https://www.cnblogs.com/wangjq19920210/p/14182776.html
Copyright © 2011-2022 走看看