(原) 动态域名服务 ddns

原创文章,请后转载,并注明出处。

我将一些服务安装到了手机里,手机可能在家里,可能在公司,可能在别处。但它的IP可能会存在变化,虽然我设置了DHCP的静态IP。
如果有一种动态域名服务装到内网,即可以将访问网络的速度变快(内网解析),又可以自动发现内网存在的设备和服务。
下面的代码是通过arp获取mac,虽说现在的手机很多都有mac变址

package main

import (
	"bytes"
	"context"
	"flag"
	"fmt"
	"log"
	"math"
	"net"
	"runtime"
	"sync"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	manuf "github.com/timest/gomanuf"
)

type info struct {
	Mac   net.HardwareAddr
	Manuf string
}

type send struct {
	ips   []net.IP
	ipNet *net.IPNet
	iface net.Interface
}

var (
	infoSet = make(map[string]info)
	ch      = make(chan bool)
)

func getIPSet(ipNet *net.IPNet) (ipSet []net.IP) {
	var ipStringSet []string
	for ip := ipNet.IP.Mask(ipNet.Mask); ipNet.Contains(ip); nextIP(ip) {
		if ip[len(ip)-1]&0xff == 0 {
			continue
		}
		ipStringSet = append(ipStringSet, ip.String())
	}
	for _, ipString := range ipStringSet {
		ip := net.ParseIP(ipString)
		if ip != nil {
			ipSet = append(ipSet, ip)
		}
	}
	return
}

func nextIP(ip net.IP) {
	for i := len(ip) - 1; i >= 0; i-- {
		ip[i]++
		if ip[i] > 0 {
			break
		}
	}
}

func (sendInfo *send) sendArpPacket(handle *pcap.Handle, ip net.IP) {
	localHaddr := sendInfo.iface.HardwareAddr
	srcIP := sendInfo.ipNet.IP.To4()
	dstIP := ip.To4()
	//fmt.Println(srcIP.String())
	//fmt.Println(dstIP.String())

	if srcIP == nil || dstIP == nil {
		log.Fatal("source address or destination address is empty!")
	}

	eth := &layers.Ethernet{
		SrcMAC:       localHaddr,
		DstMAC:       net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
		EthernetType: layers.EthernetTypeARP,
	}

	a := &layers.ARP{
		AddrType:          layers.LinkTypeEthernet,
		Protocol:          layers.EthernetTypeIPv4,
		HwAddressSize:     uint8(6),
		ProtAddressSize:   uint8(4),
		Operation:         uint16(1),
		SourceHwAddress:   localHaddr,
		SourceProtAddress: srcIP,
		DstHwAddress:      net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
		DstProtAddress:    dstIP,
	}

	buffer := gopacket.NewSerializeBuffer()
	var opt gopacket.SerializeOptions
	gopacket.SerializeLayers(buffer, opt, eth, a)
	outgoingPacket := buffer.Bytes()

	err := handle.WritePacketData(outgoingPacket)
	if err != nil {
		log.Fatal("Failed to send package")
	}
}

func listenArpPacket(handle *pcap.Handle, ctx context.Context, iface net.Interface) {
	ps := gopacket.NewPacketSource(handle, handle.LinkType())

	for {
		select {
		case <-ctx.Done():
			return
		case p := <-ps.Packets():
			arpLayer := p.Layer(layers.LayerTypeARP)
			if arpLayer != nil {
				arp, _ := arpLayer.(*layers.ARP)
				if arpLayer == nil {
					continue
				}
				if arp.Operation != layers.ARPReply || bytes.Equal([]byte(iface.HardwareAddr), arp.SourceHwAddress) {
					// This is a packet I sent.
					continue
				}
				if arp.Operation == layers.ARPReply {
					mac := net.HardwareAddr(arp.SourceHwAddress)
					m := manuf.Search(mac.String())
					if _, ok := infoSet[net.IP(arp.SourceProtAddress).String()]; !ok {
						ch <- true
						infoSet[net.IP(arp.SourceProtAddress).String()] = info{mac, m}
						ch <- false
					}
				}
			}
		}
	}
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	ifaceName := flag.String("i", "", "NetWork interface name")
	flag.Parse()
	usageTime := time.Now()

	var ifaceSet []net.Interface
	var err error

	if *ifaceName == "" {
		ifaceSet, err = net.Interfaces()
	} else {
		iface, err := net.InterfaceByName(*ifaceName)
		if err == nil {
			ifaceSet = append(ifaceSet, *iface)
		}
	}
	if err != nil {
		log.Fatal(err)
	}

	sendInfo := &send{}

	for i, n := range ifaceSet {
		fmt.Println(i, n)
	}
Loop:
	for _, it := range ifaceSet {
		if it.Flags&net.FlagUp == 0 {
			continue
		} else if it.Flags&net.FlagLoopback != 0 {
			continue
		}
		addrs, _ := it.Addrs()
		for _, addr := range addrs {
			if ip, ok := addr.(*net.IPNet); ok {
				if ip.IP.To4() != nil {
					sendInfo.ips = getIPSet(ip)
					sendInfo.ipNet = ip
					sendInfo.iface = it
					break Loop
				}
			}
		}
	}

	handle, err := pcap.OpenLive(sendInfo.iface.Name, 65536, true, pcap.BlockForever)
	if err != nil {
		log.Fatal("pcap open fail, err:", err)
	}
	defer handle.Close()

	ctx, cancel := context.WithCancel(context.Background())
	go listenArpPacket(handle, ctx, sendInfo.iface)

	maskSize, _ := sendInfo.ipNet.Mask.Size()

	fmt.Println("************【information of interface】************")
	fmt.Printf("	interfaceName : %v\n", sendInfo.iface.Name)
	fmt.Printf(" 	interfaceIP   : %v/%d\n", sendInfo.ipNet.IP, maskSize)
	fmt.Printf("*	interfaceMAC  : %v %10v\n", sendInfo.iface.HardwareAddr, "*")
	fmt.Println("****************************************************\n")

	//发送ARP包

	interval := 1
	processNum := 300
	wg := &sync.WaitGroup{}

	if len(sendInfo.ips) <= processNum {
		processNum = len(sendInfo.ips)
	} else {
		interval = int(math.Ceil(float64(len(sendInfo.ips)) / float64(processNum)))
	}

	go func() {
		for i := 0; i < len(sendInfo.ips); i += interval {
			length := i + interval
			if length >= len(sendInfo.ips) {
				length = len(sendInfo.ips)
			}
			wg.Add(1)
			go func(ips []net.IP) {
				defer wg.Done()
				for _, ip := range ips {
					sendInfo.sendArpPacket(handle, ip)
				}
			}(sendInfo.ips[i:length])
		}
		wg.Wait()
	}()

	t := time.NewTicker(10 * time.Second)
	for {
		select {
		case <-t.C:
			for ip, data := range infoSet {
				fmt.Printf("%-15s %-20s %-40s\n", ip, data.Mac, data.Manuf)
			}
			cancel()
			fmt.Printf("\nUsage time: %v\n\n", time.Since(usageTime))
			return
		case timeStamp := <-ch:
			if timeStamp {
				t.Stop()
			} else {
				t = time.NewTicker(1 * time.Second)
			}
		}
	}
}

相关文章