"Fossies" - the Fresh Open Source Software Archive

Member "AdGuardHome-0.104.3/internal/dhcpd/nclient4/client_test.go" (19 Nov 2020, 9872 Bytes) of package /linux/misc/dns/AdGuardHome-0.104.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "client_test.go": 0.104.1_vs_0.104.3.

    1 // Copyright 2018 the u-root Authors. All rights reserved.
    2 // Use of this source code is governed by a BSD-style
    3 // license that can be found in the LICENSE file.
    4 
    5 // +build linux
    6 // github.com/hugelgupf/socketpair is Linux-only
    7 // +build go1.12
    8 
    9 package nclient4
   10 
   11 import (
   12     "bytes"
   13     "context"
   14     "fmt"
   15     "net"
   16     "sync"
   17     "testing"
   18     "time"
   19 
   20     "github.com/AdguardTeam/AdGuardHome/internal/testutil"
   21     "github.com/hugelgupf/socketpair"
   22     "github.com/insomniacslk/dhcp/dhcpv4"
   23     "github.com/insomniacslk/dhcp/dhcpv4/server4"
   24 )
   25 
   26 func TestMain(m *testing.M) {
   27     testutil.DiscardLogOutput(m)
   28 }
   29 
   30 type handler struct {
   31     mu       sync.Mutex
   32     received []*dhcpv4.DHCPv4
   33 
   34     // Each received packet can have more than one response (in theory,
   35     // from different servers sending different Advertise, for example).
   36     responses [][]*dhcpv4.DHCPv4
   37 }
   38 
   39 func (h *handler) handle(conn net.PacketConn, peer net.Addr, m *dhcpv4.DHCPv4) {
   40     h.mu.Lock()
   41     defer h.mu.Unlock()
   42 
   43     h.received = append(h.received, m)
   44 
   45     if len(h.responses) > 0 {
   46         for _, resp := range h.responses[0] {
   47             _, _ = conn.WriteTo(resp.ToBytes(), peer)
   48         }
   49         h.responses = h.responses[1:]
   50     }
   51 }
   52 
   53 func serveAndClient(ctx context.Context, responses [][]*dhcpv4.DHCPv4, opts ...ClientOpt) (*Client, net.PacketConn) {
   54     // Fake PacketConn connection.
   55     clientRawConn, serverRawConn, err := socketpair.PacketSocketPair()
   56     if err != nil {
   57         panic(err)
   58     }
   59 
   60     clientConn := NewBroadcastUDPConn(clientRawConn, &net.UDPAddr{Port: ClientPort})
   61     serverConn := NewBroadcastUDPConn(serverRawConn, &net.UDPAddr{Port: ServerPort})
   62 
   63     o := []ClientOpt{WithRetry(1), WithTimeout(2 * time.Second)}
   64     o = append(o, opts...)
   65     mc, err := NewWithConn(clientConn, net.HardwareAddr{0xa, 0xb, 0xc, 0xd, 0xe, 0xf}, o...)
   66     if err != nil {
   67         panic(err)
   68     }
   69 
   70     h := &handler{responses: responses}
   71     s, err := server4.NewServer("", nil, h.handle, server4.WithConn(serverConn))
   72     if err != nil {
   73         panic(err)
   74     }
   75     go func() {
   76         _ = s.Serve()
   77     }()
   78 
   79     return mc, serverConn
   80 }
   81 
   82 func ComparePacket(got *dhcpv4.DHCPv4, want *dhcpv4.DHCPv4) error {
   83     if got == nil && got == want {
   84         return nil
   85     }
   86     if (want == nil || got == nil) && (got != want) {
   87         return fmt.Errorf("packet got %v, want %v", got, want)
   88     }
   89     if !bytes.Equal(got.ToBytes(), want.ToBytes()) {
   90         return fmt.Errorf("packet got %v, want %v", got, want)
   91     }
   92     return nil
   93 }
   94 
   95 func pktsExpected(got []*dhcpv4.DHCPv4, want []*dhcpv4.DHCPv4) error {
   96     if len(got) != len(want) {
   97         return fmt.Errorf("got %d packets, want %d packets", len(got), len(want))
   98     }
   99 
  100     for i := range got {
  101         if err := ComparePacket(got[i], want[i]); err != nil {
  102             return err
  103         }
  104     }
  105     return nil
  106 }
  107 
  108 func newPacketWeirdHWAddr(op dhcpv4.OpcodeType, xid dhcpv4.TransactionID) *dhcpv4.DHCPv4 {
  109     p, err := dhcpv4.New()
  110     if err != nil {
  111         panic(fmt.Sprintf("newpacket: %v", err))
  112     }
  113     p.OpCode = op
  114     p.TransactionID = xid
  115     p.ClientHWAddr = net.HardwareAddr{0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 1, 2, 3, 4, 5, 6}
  116     return p
  117 }
  118 
  119 func newPacket(op dhcpv4.OpcodeType, xid dhcpv4.TransactionID) *dhcpv4.DHCPv4 {
  120     p, err := dhcpv4.New()
  121     if err != nil {
  122         panic(fmt.Sprintf("newpacket: %v", err))
  123     }
  124     p.OpCode = op
  125     p.TransactionID = xid
  126     p.ClientHWAddr = net.HardwareAddr{0xa, 0xb, 0xc, 0xd, 0xe, 0xf}
  127     return p
  128 }
  129 
  130 func withBufferCap(n int) ClientOpt {
  131     return func(c *Client) (err error) {
  132         c.bufferCap = n
  133         return
  134     }
  135 }
  136 
  137 func TestSendAndRead(t *testing.T) {
  138     for _, tt := range []struct {
  139         desc   string
  140         send   *dhcpv4.DHCPv4
  141         server []*dhcpv4.DHCPv4
  142 
  143         // If want is nil, we assume server[0] contains what is wanted.
  144         want    *dhcpv4.DHCPv4
  145         wantErr error
  146     }{
  147         {
  148             desc: "two response packets",
  149             send: newPacket(dhcpv4.OpcodeBootRequest, [4]byte{0x33, 0x33, 0x33, 0x33}),
  150             server: []*dhcpv4.DHCPv4{
  151                 newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  152                 newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  153                 newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  154                 newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  155                 newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  156             },
  157             want: newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  158         },
  159         {
  160             desc: "one response packet",
  161             send: newPacket(dhcpv4.OpcodeBootRequest, [4]byte{0x33, 0x33, 0x33, 0x33}),
  162             server: []*dhcpv4.DHCPv4{
  163                 newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  164             },
  165             want: newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  166         },
  167         {
  168             desc: "one response packet, one invalid XID, one invalid opcode, one invalid hwaddr",
  169             send: newPacket(dhcpv4.OpcodeBootRequest, [4]byte{0x33, 0x33, 0x33, 0x33}),
  170             server: []*dhcpv4.DHCPv4{
  171                 newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x77, 0x33, 0x33, 0x33}),
  172                 newPacket(dhcpv4.OpcodeBootRequest, [4]byte{0x33, 0x33, 0x33, 0x33}),
  173                 newPacketWeirdHWAddr(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  174                 newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  175             },
  176             want: newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  177         },
  178         {
  179             desc: "discard wrong XID",
  180             send: newPacket(dhcpv4.OpcodeBootRequest, [4]byte{0x33, 0x33, 0x33, 0x33}),
  181             server: []*dhcpv4.DHCPv4{
  182                 newPacket(dhcpv4.OpcodeBootReply, [4]byte{0, 0, 0, 0}),
  183             },
  184             want:    nil, // Explicitly empty.
  185             wantErr: ErrNoResponse,
  186         },
  187         {
  188             desc:    "no response, timeout",
  189             send:    newPacket(dhcpv4.OpcodeBootRequest, [4]byte{0x33, 0x33, 0x33, 0x33}),
  190             wantErr: ErrNoResponse,
  191         },
  192     } {
  193         t.Run(tt.desc, func(t *testing.T) {
  194             // Both server and client only get 2 seconds.
  195             ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  196             defer cancel()
  197 
  198             mc, _ := serveAndClient(ctx, [][]*dhcpv4.DHCPv4{tt.server},
  199                 // Use an unbuffered channel to make sure we
  200                 // have no deadlocks.
  201                 withBufferCap(0))
  202             defer mc.Close()
  203 
  204             rcvd, err := mc.SendAndRead(context.Background(), DefaultServers, tt.send, nil)
  205             if err != tt.wantErr {
  206                 t.Error(err)
  207             }
  208 
  209             if err := ComparePacket(rcvd, tt.want); err != nil {
  210                 t.Errorf("got unexpected packets: %v", err)
  211             }
  212         })
  213     }
  214 }
  215 
  216 func TestParallelSendAndRead(t *testing.T) {
  217     pkt := newPacket(dhcpv4.OpcodeBootRequest, [4]byte{0x33, 0x33, 0x33, 0x33})
  218 
  219     // Both the server and client only get 2 seconds.
  220     ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  221     defer cancel()
  222 
  223     mc, _ := serveAndClient(ctx, [][]*dhcpv4.DHCPv4{},
  224         WithTimeout(10*time.Second),
  225         // Use an unbuffered channel to make sure nothing blocks.
  226         withBufferCap(0))
  227     defer mc.Close()
  228 
  229     var wg sync.WaitGroup
  230 
  231     wg.Add(1)
  232     go func() {
  233         defer wg.Done()
  234         if _, err := mc.SendAndRead(context.Background(), DefaultServers, pkt, nil); err != ErrNoResponse {
  235             t.Errorf("SendAndRead(%v) = %v, want %v", pkt, err, ErrNoResponse)
  236         }
  237     }()
  238 
  239     wg.Add(1)
  240     go func() {
  241         defer wg.Done()
  242 
  243         time.Sleep(4 * time.Second)
  244 
  245         if err := mc.Close(); err != nil {
  246             t.Errorf("closing failed: %v", err)
  247         }
  248     }()
  249 
  250     wg.Wait()
  251 }
  252 
  253 func TestReuseXID(t *testing.T) {
  254     pkt := newPacket(dhcpv4.OpcodeBootRequest, [4]byte{0x33, 0x33, 0x33, 0x33})
  255 
  256     // Both the server and client only get 2 seconds.
  257     ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  258     defer cancel()
  259 
  260     mc, _ := serveAndClient(ctx, [][]*dhcpv4.DHCPv4{})
  261     defer mc.Close()
  262 
  263     if _, err := mc.SendAndRead(context.Background(), DefaultServers, pkt, nil); err != ErrNoResponse {
  264         t.Errorf("SendAndRead(%v) = %v, want %v", pkt, err, ErrNoResponse)
  265     }
  266 
  267     if _, err := mc.SendAndRead(context.Background(), DefaultServers, pkt, nil); err != ErrNoResponse {
  268         t.Errorf("SendAndRead(%v) = %v, want %v", pkt, err, ErrNoResponse)
  269     }
  270 }
  271 
  272 func TestSimpleSendAndReadDiscardGarbage(t *testing.T) {
  273     pkt := newPacket(dhcpv4.OpcodeBootRequest, [4]byte{0x33, 0x33, 0x33, 0x33})
  274 
  275     responses := newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33})
  276 
  277     // Both the server and client only get 2 seconds.
  278     ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  279     defer cancel()
  280 
  281     mc, udpConn := serveAndClient(ctx, [][]*dhcpv4.DHCPv4{{responses}})
  282     defer mc.Close()
  283 
  284     // Too short for valid DHCPv4 packet.
  285     _, _ = udpConn.WriteTo([]byte{0x01}, nil)
  286     _, _ = udpConn.WriteTo([]byte{0x01, 0x2}, nil)
  287 
  288     rcvd, err := mc.SendAndRead(ctx, DefaultServers, pkt, nil)
  289     if err != nil {
  290         t.Errorf("SendAndRead(%v) = %v, want nil", pkt, err)
  291     }
  292 
  293     if err := ComparePacket(rcvd, responses); err != nil {
  294         t.Errorf("got unexpected packets: %v", err)
  295     }
  296 }
  297 
  298 func TestMultipleSendAndRead(t *testing.T) {
  299     for _, tt := range []struct {
  300         desc    string
  301         send    []*dhcpv4.DHCPv4
  302         server  [][]*dhcpv4.DHCPv4
  303         wantErr []error
  304     }{
  305         {
  306             desc: "two requests, two responses",
  307             send: []*dhcpv4.DHCPv4{
  308                 newPacket(dhcpv4.OpcodeBootRequest, [4]byte{0x33, 0x33, 0x33, 0x33}),
  309                 newPacket(dhcpv4.OpcodeBootRequest, [4]byte{0x44, 0x44, 0x44, 0x44}),
  310             },
  311             server: [][]*dhcpv4.DHCPv4{
  312                 []*dhcpv4.DHCPv4{ // Response for first packet.
  313                     newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x33, 0x33, 0x33, 0x33}),
  314                 },
  315                 []*dhcpv4.DHCPv4{ // Response for second packet.
  316                     newPacket(dhcpv4.OpcodeBootReply, [4]byte{0x44, 0x44, 0x44, 0x44}),
  317                 },
  318             },
  319             wantErr: []error{
  320                 nil,
  321                 nil,
  322             },
  323         },
  324     } {
  325         // Both server and client only get 2 seconds.
  326         ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  327         defer cancel()
  328 
  329         mc, _ := serveAndClient(ctx, tt.server)
  330         defer mc.Close()
  331 
  332         for i, send := range tt.send {
  333             ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
  334             defer cancel()
  335             rcvd, err := mc.SendAndRead(ctx, DefaultServers, send, nil)
  336 
  337             if wantErr := tt.wantErr[i]; err != wantErr {
  338                 t.Errorf("SendAndReadOne(%v): got %v, want %v", send, err, wantErr)
  339             }
  340             if err := pktsExpected([]*dhcpv4.DHCPv4{rcvd}, tt.server[i]); err != nil {
  341                 t.Errorf("got unexpected packets: %v", err)
  342             }
  343         }
  344     }
  345 }