github.com/mholt/caddy-l4@v0.0.0-20241104153248-ec8fae209322/modules/l4winbox/matcher_test.go (about)

     1  // Copyright 2024 VNXME
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package l4winbox
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"errors"
    21  	"io"
    22  	"net"
    23  	"testing"
    24  
    25  	"github.com/caddyserver/caddy/v2"
    26  	"go.uber.org/zap"
    27  
    28  	"github.com/mholt/caddy-l4/layer4"
    29  )
    30  
    31  func assertNoError(t *testing.T, err error) {
    32  	t.Helper()
    33  	if err != nil && !errors.Is(err, io.EOF) && !errors.Is(err, io.ErrUnexpectedEOF) {
    34  		t.Fatalf("Unexpected error: %s\n", err)
    35  	}
    36  }
    37  
    38  func Test_MessageAuth_FromBytes_ToBytes(t *testing.T) {
    39  	var msg *MessageAuth
    40  	var err error
    41  	for _, packet := range [][]byte{packetS1, packetS2, packetR1, packetR2} {
    42  		msg = &MessageAuth{}
    43  		if err = msg.FromBytes(packet); err != nil {
    44  			t.Fatalf("Failed to parse MessageAuth from bytes: %s\n", err)
    45  		}
    46  		if !bytes.Equal(packet, msg.ToBytes()) {
    47  			t.Fatalf("Bytes don't match.\nExpected: %x\nComposed: %x", packet, msg.ToBytes())
    48  		}
    49  	}
    50  }
    51  
    52  func Test_MatchWinbox_Match(t *testing.T) {
    53  	type test struct {
    54  		matcher     *MatchWinbox
    55  		data        []byte
    56  		shouldMatch bool
    57  	}
    58  
    59  	m0 := &MatchWinbox{}
    60  	m1 := &MatchWinbox{Modes: []string{ModeStandard}}
    61  	m2 := &MatchWinbox{Modes: []string{ModeRoMON}}
    62  	m3 := &MatchWinbox{Username: "toms"}
    63  	m4 := &MatchWinbox{UsernameRegexp: "^andris|edgars|juris$"}
    64  
    65  	tests := []test{
    66  		{matcher: m0, data: packetS1[:len(packetS1)-1], shouldMatch: false},
    67  		{matcher: m0, data: packetS2[:len(packetS2)-1], shouldMatch: false},
    68  		{matcher: m0, data: packetR1[:len(packetR1)-1], shouldMatch: false},
    69  		{matcher: m0, data: packetR2[:len(packetR2)-1], shouldMatch: false},
    70  
    71  		{matcher: m0, data: packetS1, shouldMatch: true},
    72  		{matcher: m0, data: packetS2, shouldMatch: true},
    73  		{matcher: m0, data: packetR1, shouldMatch: true},
    74  		{matcher: m0, data: packetR2, shouldMatch: true},
    75  
    76  		{matcher: m1, data: packetS1, shouldMatch: true},
    77  		{matcher: m1, data: packetS2, shouldMatch: true},
    78  		{matcher: m1, data: packetR1, shouldMatch: false},
    79  		{matcher: m1, data: packetR2, shouldMatch: false},
    80  
    81  		{matcher: m2, data: packetS1, shouldMatch: false},
    82  		{matcher: m2, data: packetS2, shouldMatch: false},
    83  		{matcher: m2, data: packetR1, shouldMatch: true},
    84  		{matcher: m2, data: packetR2, shouldMatch: true},
    85  
    86  		{matcher: m3, data: packetS1, shouldMatch: true},
    87  		{matcher: m3, data: packetS2, shouldMatch: false},
    88  		{matcher: m3, data: packetR1, shouldMatch: true},
    89  		{matcher: m3, data: packetR2, shouldMatch: false},
    90  
    91  		{matcher: m4, data: packetS1, shouldMatch: false},
    92  		{matcher: m4, data: packetS2, shouldMatch: true},
    93  		{matcher: m4, data: packetR1, shouldMatch: false},
    94  		{matcher: m4, data: packetR2, shouldMatch: true},
    95  	}
    96  
    97  	ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
    98  	defer cancel()
    99  
   100  	for i, tc := range tests {
   101  		func() {
   102  			err := tc.matcher.Provision(ctx)
   103  			assertNoError(t, err)
   104  
   105  			in, out := net.Pipe()
   106  			defer func() {
   107  				_, _ = io.Copy(io.Discard, out)
   108  				_ = out.Close()
   109  			}()
   110  
   111  			cx := layer4.WrapConnection(out, []byte{}, zap.NewNop())
   112  			go func() {
   113  				_, err := in.Write(tc.data)
   114  				assertNoError(t, err)
   115  				_ = in.Close()
   116  			}()
   117  
   118  			matched, err := tc.matcher.Match(cx)
   119  			assertNoError(t, err)
   120  
   121  			if matched != tc.shouldMatch {
   122  				if tc.shouldMatch {
   123  					t.Fatalf("Test %d: matcher did not match | %+v\n", i, tc.matcher)
   124  				} else {
   125  					t.Fatalf("Test %d: matcher should not match | %+v\n", i, tc.matcher)
   126  				}
   127  			}
   128  		}()
   129  	}
   130  }
   131  
   132  // Packet examples
   133  var packetS1 = []byte{38, 6, 116, 111, 109, 115, 0, 16, 224, 171, 254, 156, 62, 32, 96, 105, 79, 183, 32, 18, 98, 154, 210, 88, 231, 107, 124, 235, 252, 112, 176, 226, 63, 148, 136, 155, 149, 250, 151, 0}
   134  var packetS2 = []byte{40, 6, 97, 110, 100, 114, 105, 115, 0, 14, 185, 111, 184, 198, 199, 177, 230, 112, 205, 86, 92, 179, 165, 60, 173, 240, 56, 44, 175, 102, 201, 198, 26, 252, 174, 71, 206, 89, 58, 169, 17, 1}
   135  var packetR1 = []byte{40, 6, 116, 111, 109, 115, 43, 114, 0, 65, 165, 44, 39, 101, 48, 138, 138, 139, 207, 103, 177, 231, 74, 148, 181, 203, 140, 104, 13, 19, 95, 116, 84, 172, 115, 20, 170, 6, 178, 163, 172, 0}
   136  var packetR2 = []byte{42, 6, 97, 110, 100, 114, 105, 115, 43, 114, 0, 18, 158, 36, 11, 95, 8, 113, 35, 73, 92, 164, 206, 35, 223, 100, 63, 183, 98, 232, 182, 51, 93, 1, 56, 212, 183, 106, 169, 185, 69, 244, 81, 0}