1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- package dhcp
- import (
- "context"
- "errors"
- "net"
- "net/netip"
- "github.com/metacubex/mihomo/common/nnip"
- "github.com/metacubex/mihomo/component/iface"
- "github.com/insomniacslk/dhcp/dhcpv4"
- )
- var (
- ErrNotResponding = errors.New("DHCP not responding")
- ErrNotFound = errors.New("DNS option not found")
- )
- func ResolveDNSFromDHCP(context context.Context, ifaceName string) ([]netip.Addr, error) {
- conn, err := ListenDHCPClient(context, ifaceName)
- if err != nil {
- return nil, err
- }
- defer func() {
- _ = conn.Close()
- }()
- result := make(chan []netip.Addr, 1)
- ifaceObj, err := iface.ResolveInterface(ifaceName)
- if err != nil {
- return nil, err
- }
- discovery, err := dhcpv4.NewDiscovery(ifaceObj.HardwareAddr, dhcpv4.WithBroadcast(true), dhcpv4.WithRequestedOptions(dhcpv4.OptionDomainNameServer))
- if err != nil {
- return nil, err
- }
- go receiveOffer(conn, discovery.TransactionID, result)
- _, err = conn.WriteTo(discovery.ToBytes(), &net.UDPAddr{IP: net.IPv4bcast, Port: 67})
- if err != nil {
- return nil, err
- }
- select {
- case r, ok := <-result:
- if !ok {
- return nil, ErrNotFound
- }
- return r, nil
- case <-context.Done():
- return nil, ErrNotResponding
- }
- }
- func receiveOffer(conn net.PacketConn, id dhcpv4.TransactionID, result chan<- []netip.Addr) {
- defer close(result)
- buf := make([]byte, dhcpv4.MaxMessageSize)
- for {
- n, _, err := conn.ReadFrom(buf)
- if err != nil {
- return
- }
- pkt, err := dhcpv4.FromBytes(buf[:n])
- if err != nil {
- continue
- }
- if pkt.MessageType() != dhcpv4.MessageTypeOffer {
- continue
- }
- if pkt.TransactionID != id {
- continue
- }
- dns := pkt.DNS()
- l := len(dns)
- if l == 0 {
- return
- }
- dnsAddr := make([]netip.Addr, l)
- for i := 0; i < l; i++ {
- dnsAddr[i] = nnip.IpToAddr(dns[i])
- }
- result <- dnsAddr
- return
- }
- }
|