github.com/mholt/caddy-l4@v0.0.0-20241104153248-ec8fae209322/modules/l4rdp/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 l4rdp
    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_MatchRDP_ProcessTPKTHeader(t *testing.T) {
    39  	p := [][]byte{
    40  		packetValid1[0:4], packetValid2[0:4], packetValid3[0:4], packetValid4[0:4],
    41  		packetValid5[0:4], packetValid6[0:4], packetValid7[0:4], packetValid8[0:4], packetValid9[0:4],
    42  	}
    43  	for _, b := range p {
    44  		func() {
    45  			s := &TPKTHeader{}
    46  			errFrom := s.FromBytes(b)
    47  			assertNoError(t, errFrom)
    48  			sb, errTo := s.ToBytes()
    49  			assertNoError(t, errTo)
    50  			if !bytes.Equal(b, sb) {
    51  				t.Fatalf("test %T bytes processing: resulting bytes [% x] don't match original bytes [% x]", *s, b, sb)
    52  			}
    53  		}()
    54  	}
    55  }
    56  
    57  func Test_MatchRDP_ProcessX224Crq(t *testing.T) {
    58  	p := [][]byte{
    59  		packetValid1[4:11], packetValid2[4:11], packetValid3[4:11], packetValid4[4:11],
    60  		packetValid5[4:11], packetValid6[4:11], packetValid7[4:11], packetValid8[4:11], packetValid9[4:11],
    61  	}
    62  	for _, b := range p {
    63  		func() {
    64  			s := &X224Crq{}
    65  			errFrom := s.FromBytes(b)
    66  			assertNoError(t, errFrom)
    67  			sb, errTo := s.ToBytes()
    68  			assertNoError(t, errTo)
    69  			if !bytes.Equal(b, sb) {
    70  				t.Fatalf("test %T bytes processing: resulting bytes [% x] don't match original bytes [% x]", *s, b, sb)
    71  			}
    72  		}()
    73  	}
    74  }
    75  
    76  func Test_MatchRDP_ProcessRDPCookie(t *testing.T) {
    77  	p := [][]byte{
    78  		packetValid3[11:35], packetValid4[11:35], packetValid6[11:35],
    79  	}
    80  	for _, b := range p {
    81  		func() {
    82  			s := string(b)
    83  			if s != RDPCookiePrefix+"a0123"+string(ASCIIByteCR)+string(ASCIIByteLF) {
    84  				t.Fatalf("test RDPCookie bytes processing: resulting bytes [% x] don't match original bytes [% x]", b, []byte(s))
    85  			}
    86  		}()
    87  	}
    88  }
    89  
    90  func Test_MatchRDP_ProcessRDPToken(t *testing.T) {
    91  	p := [][]byte{
    92  		packetValid5[11:56], packetValid7[11:56], packetValid8[11:56],
    93  	}
    94  	for _, b := range p {
    95  		func() {
    96  			s := &RDPToken{}
    97  			errFrom := s.FromBytes(b)
    98  			assertNoError(t, errFrom)
    99  			sb, errTo := s.ToBytes()
   100  			assertNoError(t, errTo)
   101  			if !bytes.Equal(b, sb) {
   102  				t.Fatalf("test %T bytes processing: resulting bytes [% x] don't match original bytes [% x]", *s, b, sb)
   103  			}
   104  		}()
   105  	}
   106  }
   107  
   108  func Test_MatchRDP_ProcessRDPNegReq(t *testing.T) {
   109  	p := [][]byte{
   110  		packetValid1[11:19], packetValid2[11:19], packetValid3[35:43], packetValid4[35:43],
   111  		packetValid5[56:64], packetValid8[56:64],
   112  	}
   113  	for _, b := range p {
   114  		func() {
   115  			s := &RDPNegReq{}
   116  			errFrom := s.FromBytes(b)
   117  			assertNoError(t, errFrom)
   118  			sb, errTo := s.ToBytes()
   119  			assertNoError(t, errTo)
   120  			if !bytes.Equal(b, sb) {
   121  				t.Fatalf("test %T bytes processing: resulting bytes [% x] don't match original bytes [% x]", *s, b, sb)
   122  			}
   123  		}()
   124  	}
   125  }
   126  
   127  func Test_MatchRDP_ProcessRDPCorrInfo(t *testing.T) {
   128  	p := [][]byte{
   129  		packetValid2[19:55], packetValid3[43:79], packetValid8[64:100],
   130  	}
   131  	for _, b := range p {
   132  		func() {
   133  			s := &RDPCorrInfo{}
   134  			errFrom := s.FromBytes(b)
   135  			assertNoError(t, errFrom)
   136  			sb, errTo := s.ToBytes()
   137  			assertNoError(t, errTo)
   138  			if !bytes.Equal(b, sb) {
   139  				t.Fatalf("test %T bytes processing: resulting bytes [% x] don't match original bytes [% x]", *s, b, sb)
   140  			}
   141  		}()
   142  	}
   143  }
   144  
   145  func Test_MatchRDP_Match(t *testing.T) {
   146  	type test struct {
   147  		matcher     *MatchRDP
   148  		data        []byte
   149  		shouldMatch bool
   150  	}
   151  
   152  	tests := []test{
   153  		// without filters
   154  		{matcher: &MatchRDP{}, data: packetTooShort, shouldMatch: false},
   155  		{matcher: &MatchRDP{}, data: packetInvalid1, shouldMatch: false},
   156  		{matcher: &MatchRDP{}, data: packetInvalid2, shouldMatch: false},
   157  		{matcher: &MatchRDP{}, data: packetInvalid3, shouldMatch: false},
   158  		{matcher: &MatchRDP{}, data: packetInvalid4, shouldMatch: false},
   159  		{matcher: &MatchRDP{}, data: packetInvalid5, shouldMatch: false},
   160  		{matcher: &MatchRDP{}, data: packetInvalid6, shouldMatch: false},
   161  		{matcher: &MatchRDP{}, data: packetSemiValid1, shouldMatch: false},
   162  		{matcher: &MatchRDP{}, data: packetSemiValid2, shouldMatch: false},
   163  		{matcher: &MatchRDP{}, data: packetSemiValid3, shouldMatch: false},
   164  		{matcher: &MatchRDP{}, data: packetSemiValid4, shouldMatch: false},
   165  		{matcher: &MatchRDP{}, data: packetValid1, shouldMatch: true},
   166  		{matcher: &MatchRDP{}, data: packetValid2, shouldMatch: true},
   167  		{matcher: &MatchRDP{}, data: packetValid3, shouldMatch: true},
   168  		{matcher: &MatchRDP{}, data: packetValid4, shouldMatch: true},
   169  		{matcher: &MatchRDP{}, data: packetValid5, shouldMatch: true},
   170  		{matcher: &MatchRDP{}, data: packetValid6, shouldMatch: true},
   171  		{matcher: &MatchRDP{}, data: packetValid7, shouldMatch: true},
   172  		{matcher: &MatchRDP{}, data: packetValid8, shouldMatch: true},
   173  		{matcher: &MatchRDP{}, data: packetValid9, shouldMatch: true},
   174  		{matcher: &MatchRDP{}, data: packetExtraByte, shouldMatch: false},
   175  		// with filtered hash
   176  		{matcher: &MatchRDP{CookieHash: ""}, data: packetValid3, shouldMatch: true},
   177  		{matcher: &MatchRDP{CookieHash: "a0123"}, data: packetValid3, shouldMatch: true},
   178  		{matcher: &MatchRDP{CookieHash: "admin"}, data: packetValid3, shouldMatch: false},
   179  		{matcher: &MatchRDP{CookieHashRegexp: ""}, data: packetValid3, shouldMatch: true},
   180  		{matcher: &MatchRDP{CookieHashRegexp: "^[a-z]\\d+$"}, data: packetValid3, shouldMatch: true},
   181  		{matcher: &MatchRDP{CookieHashRegexp: "^[A-Z]\\d+$"}, data: packetValid3, shouldMatch: false},
   182  		// with filtered port
   183  		{matcher: &MatchRDP{CookiePorts: []uint16{}}, data: packetValid5, shouldMatch: true},
   184  		{matcher: &MatchRDP{CookiePorts: []uint16{3389}}, data: packetValid5, shouldMatch: true},
   185  		{matcher: &MatchRDP{CookiePorts: []uint16{5000}}, data: packetValid5, shouldMatch: false},
   186  		// with filtered IP
   187  		{matcher: &MatchRDP{CookieIPs: []string{}}, data: packetValid7, shouldMatch: true},
   188  		{matcher: &MatchRDP{CookieIPs: []string{"127.0.0.1/8"}}, data: packetValid7, shouldMatch: true},
   189  		{matcher: &MatchRDP{CookieIPs: []string{"192.168.0.1/16"}}, data: packetValid7, shouldMatch: false},
   190  		// with filtered info
   191  		{matcher: &MatchRDP{CustomInfo: ""}, data: packetValid9, shouldMatch: true},
   192  		{matcher: &MatchRDP{CustomInfo: "anything could be here"}, data: packetValid9, shouldMatch: true},
   193  		{matcher: &MatchRDP{CustomInfo: "arbitrary text"}, data: packetValid9, shouldMatch: false},
   194  		{matcher: &MatchRDP{CustomInfoRegexp: ""}, data: packetValid9, shouldMatch: true},
   195  		{matcher: &MatchRDP{CustomInfoRegexp: "^([A-Za-z0-9 ]+)$"}, data: packetValid9, shouldMatch: true},
   196  		{matcher: &MatchRDP{CustomInfoRegexp: "^\\x00\\x01\\x02\\x03\\x04$"}, data: packetValid9, shouldMatch: false},
   197  	}
   198  
   199  	ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
   200  	defer cancel()
   201  
   202  	for i, tc := range tests {
   203  		func() {
   204  			err := tc.matcher.Provision(ctx)
   205  			assertNoError(t, err)
   206  
   207  			in, out := net.Pipe()
   208  			defer func() {
   209  				_, _ = io.Copy(io.Discard, out)
   210  				_ = out.Close()
   211  			}()
   212  
   213  			cx := layer4.WrapConnection(out, []byte{}, zap.NewNop())
   214  			go func() {
   215  				_, err := in.Write(tc.data)
   216  				assertNoError(t, err)
   217  				_ = in.Close()
   218  			}()
   219  
   220  			matched, err := tc.matcher.Match(cx)
   221  			assertNoError(t, err)
   222  
   223  			if matched != tc.shouldMatch {
   224  				if tc.shouldMatch {
   225  					t.Fatalf("test %d: matcher did not match | %+v\n", i, tc.matcher)
   226  				} else {
   227  					t.Fatalf("test %d: matcher should not match | %+v\n", i, tc.matcher)
   228  				}
   229  			}
   230  		}()
   231  	}
   232  }
   233  
   234  // Packet examples
   235  var packetTooShort = []byte{
   236  	0x00, 0x00, 0x00, 0x00, // TPKTHeader
   237  }
   238  var packetInvalid1 = []byte{
   239  	0x00, 0x00, 0x00, 0x00, // TPKTHeader
   240  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   241  }
   242  var packetInvalid2 = []byte{
   243  	0x03, 0x00, 0x00, 0x0B, // TPKTHeader
   244  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   245  }
   246  var packetInvalid3 = []byte{
   247  	0x03, 0x00, 0x00, 0x13, // TPKTHeader
   248  	0x0E, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   249  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   250  }
   251  var packetInvalid4 = []byte{
   252  	0x03, 0x00, 0x00, 0x37, // TPKTHeader
   253  	0x32, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   254  	0x01, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   255  	0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (1/3)
   256  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (2/3)
   257  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (3/3)
   258  }
   259  var packetInvalid5 = []byte{
   260  	0x03, 0x00, 0x00, 0x4F, // TPKTHeader
   261  	0x4A, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   262  	0x43, 0x6F, 0x6F, 0x6B, 0x69, 0x65, 0x3A, 0x20, 0x6D, 0x73, 0x74, 0x73, 0x68, 0x61, 0x73, 0x68, 0x3D, // RDPCookie (1/3)
   263  	// RDPCookie (2/3)
   264  	0x0D, 0x0A, // RDPCookie (3/3)
   265  	0x01, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   266  	0x06, 0x00, 0x24, 0x00, // RDPCorrInfo (1/3)
   267  	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (2/3)
   268  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (3/3)
   269  }
   270  var packetInvalid6 = []byte{
   271  	0x03, 0x00, 0x00, 0x1E, // TPKTHeader
   272  	0x19, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   273  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPToken (1/1)
   274  	0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   275  }
   276  var packetSemiValid1 = []byte{ // we can't be sure it's RDP
   277  	0x03, 0x00, 0x00, 0x0B, // TPKTHeader
   278  	0x06, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   279  }
   280  var packetSemiValid2 = []byte{ // we assume cookie hash must have at least 1 symbol
   281  	0x03, 0x00, 0x00, 0x4F, // TPKTHeader
   282  	0x4A, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   283  	0x43, 0x6F, 0x6F, 0x6B, 0x69, 0x65, 0x3A, 0x20, 0x6D, 0x73, 0x74, 0x73, 0x68, 0x61, 0x73, 0x68, 0x3D, // RDPCookie (1/3)
   284  	// RDPCookie (2/3)
   285  	0x0D, 0x0A, // RDPCookie (3/3)
   286  	0x01, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   287  	0x06, 0x00, 0x24, 0x00, // RDPCorrInfo (1/3)
   288  	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (2/3)
   289  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (3/3)
   290  }
   291  var packetSemiValid3 = []byte{ // we assume custom info must have at least 1 symbol
   292  	0x03, 0x00, 0x00, 0x39, // TPKTHeader
   293  	0x34, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   294  	// RDPCustom (1/2)
   295  	0x0D, 0x0A, // RDPCustom (2/2)
   296  	0x01, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   297  	0x06, 0x00, 0x24, 0x00, // RDPCorrInfo (1/3)
   298  	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (2/3)
   299  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (3/3)
   300  }
   301  var packetSemiValid4 = []byte{ // an empty RDPToken doesn't seem to be a valid part of RDP Connection Request
   302  	0x03, 0x00, 0x00, 0x1E, // TPKTHeader
   303  	0x19, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   304  	0x03, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPToken (1/1)
   305  	0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   306  }
   307  var packetValid1 = []byte{
   308  	0x03, 0x00, 0x00, 0x13, // TPKTHeader
   309  	0x0E, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   310  	0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   311  }
   312  var packetValid2 = []byte{
   313  	0x03, 0x00, 0x00, 0x37, // TPKTHeader
   314  	0x32, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   315  	0x01, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   316  	0x06, 0x00, 0x24, 0x00, // RDPCorrInfo (1/3)
   317  	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (2/3)
   318  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (3/3)
   319  }
   320  var packetValid3 = []byte{
   321  	0x03, 0x00, 0x00, 0x4F, // TPKTHeader
   322  	0x4A, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   323  	0x43, 0x6F, 0x6F, 0x6B, 0x69, 0x65, 0x3A, 0x20, 0x6D, 0x73, 0x74, 0x73, 0x68, 0x61, 0x73, 0x68, 0x3D, // RDPCookie (1/3)
   324  	0x61, 0x30, 0x31, 0x32, 0x33, // RDPCookie (2/3)
   325  	0x0D, 0x0A, // RDPCookie (3/3)
   326  	0x01, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   327  	0x06, 0x00, 0x24, 0x00, // RDPCorrInfo (1/3)
   328  	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (2/3)
   329  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (3/3)
   330  }
   331  var packetValid4 = []byte{
   332  	0x03, 0x00, 0x00, 0x2B, // TPKTHeader
   333  	0x26, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   334  	0x43, 0x6F, 0x6F, 0x6B, 0x69, 0x65, 0x3A, 0x20, 0x6D, 0x73, 0x74, 0x73, 0x68, 0x61, 0x73, 0x68, 0x3D, // RDPCookie (1/3)
   335  	0x61, 0x30, 0x31, 0x32, 0x33, // RDPCookie (2/3)
   336  	0x0D, 0x0A, // RDPCookie (3/3)
   337  	0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   338  }
   339  var packetValid5 = []byte{
   340  	0x03, 0x00, 0x00, 0x40, // TPKTHeader
   341  	0x3B, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   342  	0x03, 0x00, 0x00, 0x2D, 0x28, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPToken (1/6)
   343  	0x43, 0x6F, 0x6F, 0x6B, 0x69, 0x65, 0x3A, 0x20, 0x6D, 0x73, 0x74, 0x73, 0x3D, // RDPToken (2/6)
   344  	0x31, 0x36, 0x37, 0x37, 0x37, 0x33, 0x34, 0x33, // RDPToken (3/6)
   345  	0x2E, 0x31, 0x35, 0x36, 0x32, 0x39, // RDPToken (4/6)
   346  	0x2E, 0x30, 0x30, 0x30, 0x30, // RDPToken (5/6)
   347  	0x0D, 0x0A, // RDPToken (6/6)
   348  	0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   349  }
   350  var packetValid6 = []byte{
   351  	0x03, 0x00, 0x00, 0x23, // TPKTHeader
   352  	0x1E, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   353  	0x43, 0x6F, 0x6F, 0x6B, 0x69, 0x65, 0x3A, 0x20, 0x6D, 0x73, 0x74, 0x73, 0x68, 0x61, 0x73, 0x68, 0x3D, // RDPCookie (1/3)
   354  	0x61, 0x30, 0x31, 0x32, 0x33, // RDPCookie (2/3)
   355  	0x0D, 0x0A, // RDPCookie (3/3)
   356  }
   357  var packetValid7 = []byte{
   358  	0x03, 0x00, 0x00, 0x38, // TPKTHeader
   359  	0x33, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   360  	0x03, 0x00, 0x00, 0x2D, 0x28, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPToken (1/6)
   361  	0x43, 0x6F, 0x6F, 0x6B, 0x69, 0x65, 0x3A, 0x20, 0x6D, 0x73, 0x74, 0x73, 0x3D, // RDPToken (2/6)
   362  	0x31, 0x36, 0x37, 0x37, 0x37, 0x33, 0x34, 0x33, // RDPToken (3/6)
   363  	0x2E, 0x31, 0x35, 0x36, 0x32, 0x39, // RDPToken (4/6)
   364  	0x2E, 0x30, 0x30, 0x30, 0x30, // RDPToken (5/6)
   365  	0x0D, 0x0A, // RDPToken (6/6)
   366  }
   367  var packetValid8 = []byte{
   368  	0x03, 0x00, 0x00, 0x64, // TPKTHeader
   369  	0x5F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   370  	0x03, 0x00, 0x00, 0x2D, 0x28, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPToken (1/6)
   371  	0x43, 0x6F, 0x6F, 0x6B, 0x69, 0x65, 0x3A, 0x20, 0x6D, 0x73, 0x74, 0x73, 0x3D, // RDPToken (2/6)
   372  	0x31, 0x36, 0x37, 0x37, 0x37, 0x33, 0x34, 0x33, // RDPToken (3/6)
   373  	0x2E, 0x31, 0x35, 0x36, 0x32, 0x39, // RDPToken (4/6)
   374  	0x2E, 0x30, 0x30, 0x30, 0x30, // RDPToken (5/6)
   375  	0x0D, 0x0A, // RDPToken (6/6)
   376  	0x01, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   377  	0x06, 0x00, 0x24, 0x00, // RDPCorrInfo (1/3)
   378  	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (2/3)
   379  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (3/3)
   380  }
   381  var packetValid9 = []byte{
   382  	0x03, 0x00, 0x00, 0x23, // TPKTHeader
   383  	0x1E, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   384  	0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, // RDPCustom (1/3)
   385  	0x62, 0x65, 0x20, 0x68, 0x65, 0x72, 0x65, // RDPCustom (2/3)
   386  	0x0D, 0x0A, // RDPCustom (3/3)
   387  }
   388  var packetExtraByte = []byte{
   389  	0x03, 0x00, 0x00, 0x64, // TPKTHeader
   390  	0x5F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // X224Crq
   391  	0x03, 0x00, 0x00, 0x2D, 0x28, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPToken (1/6)
   392  	0x43, 0x6F, 0x6F, 0x6B, 0x69, 0x65, 0x3A, 0x20, 0x6D, 0x73, 0x74, 0x73, 0x3D, // RDPToken (2/6)
   393  	0x31, 0x36, 0x37, 0x37, 0x37, 0x33, 0x34, 0x33, // RDPToken (3/6)
   394  	0x2E, 0x31, 0x35, 0x36, 0x32, 0x39, // RDPToken (4/6)
   395  	0x2E, 0x30, 0x30, 0x30, 0x30, // RDPToken (5/6)
   396  	0x0D, 0x0A, // RDPToken (6/6)
   397  	0x01, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPNegReq
   398  	0x06, 0x00, 0x24, 0x00, // RDPCorrInfo (1/3)
   399  	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (2/3)
   400  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RDPCorrInfo (3/3)
   401  	0x00, // wrong byte
   402  }