Skip to content

Commit 4c72479

Browse files
committedOct 26, 2020
[tests] Add tests ensuring pmp messages decode correctly
We definitely handle big endian integers correctly now.
1 parent 46f5f31 commit 4c72479

File tree

3 files changed

+134
-3
lines changed

3 files changed

+134
-3
lines changed
 
+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//
2+
// Authors:
3+
// Alan McGovern <alan.mcgovern@gmail.com>
4+
//
5+
// Copyright (C) 2020 Alan McGovern
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining
8+
// a copy of this software and associated documentation files (the
9+
// "Software"), to deal in the Software without restriction, including
10+
// without limitation the rights to use, copy, modify, merge, publish,
11+
// distribute, sublicense, and/or sell copies of the Software, and to
12+
// permit persons to whom the Software is furnished to do so, subject to
13+
// the following conditions:
14+
//
15+
// The above copyright notice and this permission notice shall be
16+
// included in all copies or substantial portions of the Software.
17+
//
18+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22+
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23+
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24+
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25+
//
26+
27+
using System;
28+
using System.Net;
29+
30+
using NUnit.Framework;
31+
32+
namespace Mono.Nat.Pmp.Tests
33+
{
34+
[TestFixture]
35+
public class ResponseMessageTests
36+
{
37+
byte[] CreateResponseData (int privatePort, int publicPort, bool tcp, int lifetime, bool success, byte? opCode = null)
38+
{
39+
var response = new byte[16];
40+
//version 0
41+
response[0] = 0;
42+
43+
// operation code (tcp or udp)
44+
response[1] = opCode.HasValue ? opCode.Value : (byte) (128 + (tcp ? 2 : 1));
45+
46+
// successful error code
47+
response[2] = response[3] = (byte) (success ? 0 : 1);
48+
49+
// unix epoch
50+
response[4] = 0;
51+
response[5] = 0;
52+
response[6] = 0;
53+
response[7] = 1;
54+
55+
// private port
56+
response[8] = (byte) (IPAddress.HostToNetworkOrder (privatePort) >> 16);
57+
response[9] = (byte) (IPAddress.HostToNetworkOrder (privatePort) >> 24);
58+
59+
// public port
60+
response[10] = (byte) (IPAddress.HostToNetworkOrder (publicPort) >> 16);
61+
response[11] = (byte) (IPAddress.HostToNetworkOrder (publicPort) >> 24);
62+
63+
// lifetime
64+
response[12] = (byte) (IPAddress.HostToNetworkOrder (lifetime) >> 0);
65+
response[13] = (byte) (IPAddress.HostToNetworkOrder (lifetime) >> 8);
66+
response[14] = (byte) (IPAddress.HostToNetworkOrder (lifetime) >> 16);
67+
response[15] = (byte) (IPAddress.HostToNetworkOrder (lifetime) >> 24);
68+
69+
return response;
70+
}
71+
72+
[Test]
73+
public void InvalidOpcode ()
74+
{
75+
var data = CreateResponseData (65500, 65501, true, 66, true, opCode: 123);
76+
Assert.Throws<NotSupportedException> (() => ResponseMessage.Decode (data));
77+
}
78+
79+
[Test]
80+
public void HighPortNumber_TCP ()
81+
{
82+
var data = CreateResponseData (65500, 65501, true, 66, true);
83+
var msg = ResponseMessage.Decode (data).Mapping;
84+
Assert.AreEqual (65500, msg.PrivatePort);
85+
Assert.AreEqual (65501, msg.PublicPort);
86+
Assert.AreEqual (msg.Protocol, Protocol.Tcp);
87+
Assert.AreEqual (66, msg.Lifetime);
88+
}
89+
90+
[Test]
91+
public void HighPortNumber_UDP ()
92+
{
93+
var data = CreateResponseData (65500, 65501, false, 66, true);
94+
var msg = ResponseMessage.Decode (data).Mapping;
95+
Assert.AreEqual (65500, msg.PrivatePort);
96+
Assert.AreEqual (65501, msg.PublicPort);
97+
Assert.AreEqual (msg.Protocol, Protocol.Udp);
98+
Assert.AreEqual (66, msg.Lifetime);
99+
}
100+
101+
[Test]
102+
public void LowPortNumber_UDP ()
103+
{
104+
var data = CreateResponseData (55, 56, false, 123, true);
105+
var msg = ResponseMessage.Decode (data).Mapping;
106+
Assert.AreEqual (55, msg.PrivatePort);
107+
Assert.AreEqual (56, msg.PublicPort);
108+
Assert.AreEqual (msg.Protocol, Protocol.Udp);
109+
Assert.AreEqual (123, msg.Lifetime);
110+
}
111+
112+
[Test]
113+
public void LowPortNumber_TCP ()
114+
{
115+
var data = CreateResponseData (55, 56, true, int.MaxValue, true);
116+
var msg = ResponseMessage.Decode (data).Mapping;
117+
Assert.AreEqual (55, msg.PrivatePort);
118+
Assert.AreEqual (56, msg.PublicPort);
119+
Assert.AreEqual (msg.Protocol, Protocol.Tcp);
120+
Assert.AreEqual (int.MaxValue, msg.Lifetime);
121+
}
122+
123+
}
124+
}

‎Mono.Nat/AssemblyInfo.cs

+3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
using System;
22
using System.Reflection;
3+
using System.Runtime.CompilerServices;
34
using System.Runtime.InteropServices;
45

56
[assembly: AssemblyDescription (".NET Library for automatic network address translation")]
67
[assembly: ComVisible (false)]
78

89
[assembly: CLSCompliant (true)]
10+
11+
[assembly: InternalsVisibleTo ("Mono.Nat.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000011000000b17b4e599dad6577a40d6268fbba8496844301bca35df22bea69c2945ed9d11895bca316e94ba512031a6479c150addf9f2679ed54bb4d2460d5f197b139264137c1116734e6d3a634e1ea5f01e07eaf4c8efbe7018ec4be91ed0c0c81dca009f90d7d777a4c0c1845b9f7fcac2167368ed50d4902ec53100186c464607749cf")]

‎Mono.Nat/Pmp/Messages/Responses/ResponseMessage.cs

+7-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ namespace Mono.Nat.Pmp
3131
{
3232
class ResponseMessage
3333
{
34-
public static ResponseMessage Decode (byte[] data)
34+
public static MappingResponseMessage Decode (byte[] data)
3535
{
3636
if (data.Length < 16)
3737
throw new MappingException ($"The received message was too short, only {data.Length} bytes");
@@ -44,12 +44,16 @@ public static ResponseMessage Decode (byte[] data)
4444
Protocol protocol = Protocol.Tcp;
4545
if (opCode == PmpConstants.OperationCodeUdp)
4646
protocol = Protocol.Udp;
47+
else if (opCode == PmpConstants.OperationCodeTcp)
48+
protocol = Protocol.Tcp;
49+
else if (opCode > PmpConstants.OperationCodeTcp)
50+
throw new NotSupportedException ($"Unknown opcode: #{opCode}");
4751

4852
var resultCode = (ErrorCode) IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (data, 2));
4953
uint epoch = (uint) IPAddress.NetworkToHostOrder (BitConverter.ToInt32 (data, 4));
5054

51-
int privatePort = (ushort)IPAddress.NetworkToHostOrder ((short) BitConverter.ToUInt16 (data, 8));
52-
int publicPort = (ushort)IPAddress.NetworkToHostOrder ((short) BitConverter.ToUInt16 (data, 10));
55+
int privatePort = (ushort) IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (data, 8));
56+
int publicPort = (ushort) IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (data, 10));
5357

5458
uint lifetime = (uint) IPAddress.NetworkToHostOrder (BitConverter.ToInt32 (data, 12));
5559

0 commit comments

Comments
 (0)
Please sign in to comment.