Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
P
Pcap-Net
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Pcap-Net
Commits
343e7103
Commit
343e7103
authored
Oct 03, 2014
by
Brickner_cp
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for layers over IPv6.
parent
e7f558c9
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
414 additions
and
256 deletions
+414
-256
IpV6AddressExtensions.cs
PcapDotNet/src/PcapDotNet.Core.Test/IpV6AddressExtensions.cs
+18
-0
PcapDotNet.Core.Test.csproj
...tNet/src/PcapDotNet.Core.Test/PcapDotNet.Core.Test.csproj
+1
-0
WiresharkDatagramComparer.cs
...Net/src/PcapDotNet.Core.Test/WiresharkDatagramComparer.cs
+4
-2
WiresharkDatagramComparerIgmp.cs
...src/PcapDotNet.Core.Test/WiresharkDatagramComparerIgmp.cs
+5
-4
WiresharkDatagramComparerIpV4.cs
...src/PcapDotNet.Core.Test/WiresharkDatagramComparerIpV4.cs
+5
-0
WiresharkDatagramComparerIpV6.cs
...src/PcapDotNet.Core.Test/WiresharkDatagramComparerIpV6.cs
+26
-10
WiresharkDatagramComparerIpV6AuthenticationHeader.cs
...Test/WiresharkDatagramComparerIpV6AuthenticationHeader.cs
+5
-0
WiresharkDatagramComparerIpV6MobilityHeader.cs
....Core.Test/WiresharkDatagramComparerIpV6MobilityHeader.cs
+1
-1
WiresharkDatagramComparerTcp.cs
.../src/PcapDotNet.Core.Test/WiresharkDatagramComparerTcp.cs
+7
-4
WiresharkDatagramComparerUdp.cs
.../src/PcapDotNet.Core.Test/WiresharkDatagramComparerUdp.cs
+4
-3
DataSegment.cs
PcapDotNet/src/PcapDotNet.Packets/DataSegment.cs
+21
-1
IpDatagram.cs
PcapDotNet/src/PcapDotNet.Packets/Ip/IpDatagram.cs
+250
-0
IpV4Datagram.cs
PcapDotNet/src/PcapDotNet.Packets/IpV4/IpV4Datagram.cs
+16
-157
IpV6ExtensionHeader.cs
...tNet.Packets/IpV6/ExtensionHeaders/IpV6ExtensionHeader.cs
+0
-24
IpV6ExtensionHeaderAuthentication.cs
...pV6/ExtensionHeaders/IpV6ExtensionHeaderAuthentication.cs
+0
-13
IpV6ExtensionHeaderEncapsulatingSecurityPayload.cs
...eaders/IpV6ExtensionHeaderEncapsulatingSecurityPayload.cs
+0
-6
IpV6ExtensionHeaderStandard.cs
...kets/IpV6/ExtensionHeaders/IpV6ExtensionHeaderStandard.cs
+0
-12
IpV6ExtensionHeaders.cs
...Net.Packets/IpV6/ExtensionHeaders/IpV6ExtensionHeaders.cs
+4
-0
IpV6Datagram.cs
PcapDotNet/src/PcapDotNet.Packets/IpV6/IpV6Datagram.cs
+46
-19
PcapDotNet.Packets.csproj
PcapDotNet/src/PcapDotNet.Packets/PcapDotNet.Packets.csproj
+1
-0
No files found.
PcapDotNet/src/PcapDotNet.Core.Test/IpV6AddressExtensions.cs
0 → 100644
View file @
343e7103
using
PcapDotNet.Packets.IpV6
;
namespace
PcapDotNet.Core.Test
{
internal
static
class
IpV6AddressExtensions
{
public
static
string
GetWiresharkString
(
this
IpV6Address
address
)
{
string
str
=
address
.
ToString
(
"x"
);
if
(
str
.
StartsWith
(
"0:0:"
))
str
=
"::"
+
str
.
Substring
(
4
);
if
(
str
.
EndsWith
(
":0:0"
))
str
=
str
.
Substring
(
0
,
str
.
Length
-
4
)
+
"::"
;
str
=
str
.
Replace
(
":0:0:"
,
"::"
);
return
str
;
}
}
}
\ No newline at end of file
PcapDotNet/src/PcapDotNet.Core.Test/PcapDotNet.Core.Test.csproj
View file @
343e7103
...
...
@@ -134,6 +134,7 @@
</ItemGroup>
<ItemGroup>
<Compile
Include=
"BerkeleyPacketFilterTests.cs"
/>
<Compile
Include=
"IpV6AddressExtensions.cs"
/>
<Compile
Include=
"LivePacketDeviceExtensionsTests.cs"
/>
<Compile
Include=
"LivePacketDeviceTests.cs"
/>
<Compile
Include=
"MarshalingServicesTests.cs"
/>
...
...
PcapDotNet/src/PcapDotNet.Core.Test/WiresharkDatagramComparer.cs
View file @
343e7103
...
...
@@ -27,7 +27,8 @@ namespace PcapDotNet.Core.Test
if
(
Ignore
(
datagram
))
return
null
;
CompareDatagram
(
layer
,
datagramParent
as
Datagram
,
datagram
);
if
(!
CompareDatagram
(
layer
,
datagramParent
as
Datagram
,
datagram
))
return
null
;
return
datagram
;
}
...
...
@@ -40,7 +41,7 @@ namespace PcapDotNet.Core.Test
return
false
;
}
protected
void
CompareDatagram
(
XElement
layer
,
Datagram
parentDatagram
,
Datagram
datagram
)
protected
bool
CompareDatagram
(
XElement
layer
,
Datagram
parentDatagram
,
Datagram
datagram
)
{
bool
success
=
true
;
foreach
(
var
element
in
layer
.
Fields
())
...
...
@@ -53,6 +54,7 @@ namespace PcapDotNet.Core.Test
}
WiresharkCompareTests
.
CompareProtocols
(
datagram
,
layer
,
success
);
return
success
;
}
public
static
WiresharkDatagramComparer
GetComparer
(
string
name
,
int
count
,
bool
parentLayerSuccess
)
...
...
PcapDotNet/src/PcapDotNet.Core.Test/WiresharkDatagramComparerIgmp.cs
View file @
343e7103
...
...
@@ -44,7 +44,8 @@ namespace PcapDotNet.Core.Test
break
;
case
"igmp.checksum_bad"
:
field
.
AssertShowDecimal
(!
igmpDatagram
.
IsChecksumCorrect
);
if
(
igmpDatagram
.
IsValid
)
field
.
AssertShowDecimal
(!
igmpDatagram
.
IsChecksumCorrect
);
break
;
case
"igmp.num_grp_recs"
:
...
...
@@ -59,10 +60,10 @@ namespace PcapDotNet.Core.Test
break
;
case
IgmpMessageType
.
MembershipQuery
:
CompareDatagram
(
field
,
null
,
igmpDatagram
);
break
;
return
CompareDatagram
(
field
,
null
,
igmpDatagram
);
case
IgmpMessageType
.
MulticastTraceRouteResponse
:
case
IgmpMessageType
.
MulticastTraceRoute
:
// todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt.
break
;
...
...
@@ -108,7 +109,7 @@ namespace PcapDotNet.Core.Test
case
"igmp.mtrace.resp_ttl"
:
case
"igmp.mtrace.q_id"
:
// todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt.
Assert
.
AreEqual
(
IgmpMessageType
.
MulticastTraceRouteResponse
,
igmpDatagram
.
MessageType
);
Assert
.
IsTrue
(
new
[]
{
IgmpMessageType
.
MulticastTraceRouteResponse
,
IgmpMessageType
.
MulticastTraceRoute
}.
Contains
(
igmpDatagram
.
MessageType
)
);
break
;
default
:
...
...
PcapDotNet/src/PcapDotNet.Core.Test/WiresharkDatagramComparerIpV4.cs
View file @
343e7103
...
...
@@ -86,6 +86,11 @@ namespace PcapDotNet.Core.Test
case
"ip.checksum"
:
field
.
AssertShowHex
(
ipV4Datagram
.
HeaderChecksum
);
if
(
field
.
Showname
().
EndsWith
(
" [not all data available]"
))
{
Assert
.
IsFalse
(
ipV4Datagram
.
IsValid
);
break
;
}
foreach
(
var
checksumField
in
field
.
Fields
())
{
switch
(
checksumField
.
Name
())
...
...
PcapDotNet/src/PcapDotNet.Core.Test/WiresharkDatagramComparerIpV6.cs
View file @
343e7103
...
...
@@ -72,7 +72,7 @@ namespace PcapDotNet.Core.Test
case
"ipv6.src"
:
case
"ipv6.src_host"
:
field
.
AssertShow
(
ipV6Datagram
.
Source
.
ToString
(
"x"
));
field
.
AssertShow
(
ipV6Datagram
.
Source
.
GetWiresharkString
(
));
field
.
AssertNoFields
();
break
;
...
...
@@ -85,21 +85,34 @@ namespace PcapDotNet.Core.Test
case
"ipv6.dst"
:
case
"ipv6.dst_host"
:
field
.
AssertShow
(
ipV6Datagram
.
CurrentDestination
.
ToString
(
"x"
));
field
.
AssertShow
(
ipV6Datagram
.
CurrentDestination
.
GetWiresharkString
(
));
field
.
AssertNoFields
();
break
;
case
"ipv6.addr"
:
case
"ipv6.host"
:
Assert
.
IsTrue
(
field
.
Show
()
==
ipV6Datagram
.
Source
.
ToString
(
"x"
)
||
field
.
Show
()
==
ipV6Datagram
.
CurrentDestination
.
ToString
(
"x"
));
Assert
.
IsTrue
(
field
.
Show
()
==
ipV6Datagram
.
Source
.
GetWiresharkString
(
)
||
field
.
Show
()
==
ipV6Datagram
.
CurrentDestination
.
GetWiresharkString
(
));
field
.
AssertNoFields
();
break
;
case
"ipv6.hop_opt"
:
IpV6ExtensionHeaderHopByHopOptions
hopByHopOptions
=
(
IpV6ExtensionHeaderHopByHopOptions
)
ipV6Datagram
.
ExtensionHeaders
[
_currentExtensionHeaderIndex
];
IncrementCurrentExtensionHeaderIndex
(
ipV6Datagram
);
CompareOptions
(
field
,
ref
optionsIndex
,
hopByHopOptions
);
if
(
_currentExtensionHeaderIndex
>=
ipV6Datagram
.
ExtensionHeaders
.
Headers
.
Count
)
{
Assert
.
IsFalse
(
ipV6Datagram
.
ExtensionHeaders
.
IsValid
);
int
length
=
int
.
Parse
(
field
.
Fields
().
Where
(
subfield
=>
subfield
.
Name
()
==
""
&&
subfield
.
Show
().
StartsWith
(
"Length:"
)).
Select
(
subfield
=>
subfield
.
Show
().
Split
(
new
[]
{
':'
,
'('
,
' '
},
StringSplitOptions
.
RemoveEmptyEntries
)[
2
]).
First
());
int
maxLength
=
ipV6Datagram
.
Length
-
IpV6Datagram
.
HeaderLength
-
ipV6Datagram
.
ExtensionHeaders
.
BytesLength
;
MoreAssert
.
IsBigger
(
maxLength
,
length
);
}
else
{
IpV6ExtensionHeaderHopByHopOptions
hopByHopOptions
=
(
IpV6ExtensionHeaderHopByHopOptions
)
ipV6Datagram
.
ExtensionHeaders
[
_currentExtensionHeaderIndex
];
IncrementCurrentExtensionHeaderIndex
(
ipV6Datagram
);
CompareOptions
(
field
,
ref
optionsIndex
,
hopByHopOptions
);
}
break
;
case
"ipv6.routing_hdr"
:
...
...
@@ -237,12 +250,14 @@ namespace PcapDotNet.Core.Test
break
;
case
"ipv6.opt.pad1"
:
Assert
.
AreEqual
(
IpV6OptionType
.
Pad1
,
header
.
Options
[
optionsIndex
++].
OptionType
);
if
(
header
.
Options
.
IsValid
)
Assert
.
AreEqual
(
IpV6OptionType
.
Pad1
,
header
.
Options
[
optionsIndex
++].
OptionType
);
break
;
case
"ipv6.opt.padn"
:
Assert
.
AreEqual
(
IpV6OptionType
.
PadN
,
header
.
Options
[
optionsIndex
].
OptionType
);
headerField
.
AssertShowDecimal
(
header
.
Options
[
optionsIndex
++].
Length
);
if
(
header
.
Options
.
IsValid
)
headerField
.
AssertShowDecimal
(
header
.
Options
[
optionsIndex
++].
Length
);
break
;
case
"ipv6.mipv6_type"
:
...
...
@@ -299,7 +314,8 @@ namespace PcapDotNet.Core.Test
break
;
case
"Length"
:
Assert
.
IsTrue
(
headerFieldShowValue
.
EndsWith
(
" ("
+
header
.
Length
+
" bytes)"
));
if
(
header
.
IsValid
)
Assert
.
IsTrue
(
headerFieldShowValue
.
EndsWith
(
" ("
+
header
.
Length
+
" bytes)"
));
break
;
case
"Router alert"
:
...
...
PcapDotNet/src/PcapDotNet.Core.Test/WiresharkDatagramComparerIpV6AuthenticationHeader.cs
View file @
343e7103
...
...
@@ -29,6 +29,11 @@ namespace PcapDotNet.Core.Test
do
{
++
_currentExtensionHeaderIndex
;
if
(
_currentExtensionHeaderIndex
>=
ipV6Datagram
.
ExtensionHeaders
.
Headers
.
Count
)
{
Assert
.
IsFalse
(
ipV6Datagram
.
ExtensionHeaders
.
IsValid
);
return
false
;
}
}
while
(
ipV6Datagram
.
ExtensionHeaders
[
_currentExtensionHeaderIndex
].
Protocol
!=
IpV4Protocol
.
AuthenticationHeader
);
--
_count
;
}
...
...
PcapDotNet/src/PcapDotNet.Core.Test/WiresharkDatagramComparerIpV6MobilityHeader.cs
View file @
343e7103
...
...
@@ -787,7 +787,7 @@ namespace PcapDotNet.Core.Test
break
;
case
IpV6MobilityOptionType
.
MobileNodeIdentifier
:
optionField
.
AssertShow
(
"Mobile Node Identifier"
);
Assert
.
IsTrue
(
optionField
.
Show
().
StartsWith
(
"Mobile Node Identifier"
)
);
IpV6MobilityOptionMobileNodeIdentifier
mobileNodeIdentifier
=
(
IpV6MobilityOptionMobileNodeIdentifier
)
option
;
foreach
(
XElement
optionSubfield
in
optionField
.
Fields
())
{
...
...
PcapDotNet/src/PcapDotNet.Core.Test/WiresharkDatagramComparerTcp.cs
View file @
343e7103
...
...
@@ -4,6 +4,7 @@ using System.Text;
using
System.Xml.Linq
;
using
Microsoft.VisualStudio.TestTools.UnitTesting
;
using
PcapDotNet.Packets
;
using
PcapDotNet.Packets.Ip
;
using
PcapDotNet.Packets.IpV4
;
using
PcapDotNet.Packets.Transport
;
using
PcapDotNet.TestUtils
;
...
...
@@ -19,7 +20,7 @@ namespace PcapDotNet.Core.Test
protected
override
bool
CompareField
(
XElement
field
,
Datagram
parentDatagram
,
Datagram
datagram
)
{
Ip
V4Datagram
ipV4Datagram
=
(
IpV4
Datagram
)
parentDatagram
;
Ip
Datagram
ipDatagram
=
(
Ip
Datagram
)
parentDatagram
;
TcpDatagram
tcpDatagram
=
(
TcpDatagram
)
datagram
;
switch
(
field
.
Name
())
...
...
@@ -126,7 +127,8 @@ namespace PcapDotNet.Core.Test
case
"tcp.checksum"
:
field
.
AssertShowHex
(
tcpDatagram
.
Checksum
);
if
(!
ipV4Datagram
.
Options
.
IsBadForWireshark
())
IpV4Datagram
ipV4Datagram
=
ipDatagram
as
IpV4Datagram
;
if
(
ipV4Datagram
!=
null
&&
!
ipV4Datagram
.
Options
.
IsBadForWireshark
())
{
foreach
(
var
checksumField
in
field
.
Fields
())
{
...
...
@@ -134,11 +136,11 @@ namespace PcapDotNet.Core.Test
switch
(
checksumField
.
Name
())
{
case
"tcp.checksum_good"
:
checksumField
.
AssertShowDecimal
(
tcpDatagram
.
Checksum
!=
0
&&
ip
V4
Datagram
.
IsTransportChecksumCorrect
);
checksumField
.
AssertShowDecimal
(
tcpDatagram
.
Checksum
!=
0
&&
ipDatagram
.
IsTransportChecksumCorrect
);
break
;
case
"tcp.checksum_bad"
:
checksumField
.
AssertShowDecimal
(
tcpDatagram
.
Checksum
!=
0
&&
!
ip
V4
Datagram
.
IsTransportChecksumCorrect
);
checksumField
.
AssertShowDecimal
(
tcpDatagram
.
Checksum
!=
0
&&
!
ipDatagram
.
IsTransportChecksumCorrect
);
break
;
default
:
...
...
@@ -183,6 +185,7 @@ namespace PcapDotNet.Core.Test
Assert
.
IsFalse
(
options
.
IsValid
,
"Options IsValid"
);
Assert
.
IsTrue
(
field
.
Show
().
StartsWith
(
"Unknown (0x0a) "
)
||
// Unknown in Wireshark but known (and invalid) in Pcap.Net
field
.
Show
().
StartsWith
(
"Echo reply (with option length = "
)
||
field
.
Show
().
Contains
(
"bytes says option goes past end of options"
)
||
field
.
Show
().
Contains
(
") (with too-short option length = "
)
||
field
.
Show
().
EndsWith
(
" (length byte past end of options)"
),
...
...
PcapDotNet/src/PcapDotNet.Core.Test/WiresharkDatagramComparerUdp.cs
View file @
343e7103
...
...
@@ -2,6 +2,7 @@
using
System.Xml.Linq
;
using
Microsoft.VisualStudio.TestTools.UnitTesting
;
using
PcapDotNet.Packets
;
using
PcapDotNet.Packets.Ip
;
using
PcapDotNet.Packets.IpV4
;
using
PcapDotNet.Packets.Transport
;
...
...
@@ -16,7 +17,7 @@ namespace PcapDotNet.Core.Test
protected
override
bool
CompareField
(
XElement
field
,
Datagram
parentDatagram
,
Datagram
datagram
)
{
Ip
V4Datagram
ipV4Datagram
=
(
IpV4
Datagram
)
parentDatagram
;
Ip
Datagram
ipDatagram
=
(
Ip
Datagram
)
parentDatagram
;
UdpDatagram
udpDatagram
=
(
UdpDatagram
)
datagram
;
switch
(
field
.
Name
())
...
...
@@ -47,12 +48,12 @@ namespace PcapDotNet.Core.Test
switch
(
checksumField
.
Name
())
{
case
"udp.checksum_good"
:
checksumField
.
AssertShowDecimal
(
ip
V4
Datagram
.
IsTransportChecksumCorrect
);
checksumField
.
AssertShowDecimal
(
ipDatagram
.
IsTransportChecksumCorrect
);
break
;
case
"udp.checksum_bad"
:
if
(
checksumField
.
Show
()
==
"1"
)
Assert
.
IsFalse
(
ip
V4
Datagram
.
IsTransportChecksumCorrect
);
Assert
.
IsFalse
(
ipDatagram
.
IsTransportChecksumCorrect
);
else
checksumField
.
AssertShowDecimal
(
0
);
break
;
...
...
PcapDotNet/src/PcapDotNet.Packets/DataSegment.cs
View file @
343e7103
...
...
@@ -375,9 +375,29 @@ namespace PcapDotNet.Packets
return
sum
;
}
internal
static
uint
Sum16Bits
(
IpV6Address
address
)
{
return
Sum16Bits
(
address
.
ToValue
());
}
internal
static
uint
Sum16Bits
(
IpV4Address
address
)
{
uint
value
=
address
.
ToValue
();
return
Sum16Bits
(
address
.
ToValue
());
}
internal
static
uint
Sum16Bits
(
UInt128
value
)
{
return
Sum16Bits
((
ulong
)(
value
>>
64
))
+
Sum16Bits
((
ulong
)
value
);
}
internal
static
uint
Sum16Bits
(
ulong
value
)
{
return
Sum16Bits
((
uint
)(
value
>>
32
))
+
Sum16Bits
((
uint
)
value
);
}
internal
static
uint
Sum16Bits
(
uint
value
)
{
return
(
value
>>
16
)
+
(
value
&
0xFFFF
);
}
...
...
PcapDotNet/src/PcapDotNet.Packets/Ip/IpDatagram.cs
0 → 100644
View file @
343e7103
using
PcapDotNet.Packets.Gre
;
using
PcapDotNet.Packets.Icmp
;
using
PcapDotNet.Packets.Igmp
;
using
PcapDotNet.Packets.IpV4
;
using
PcapDotNet.Packets.IpV6
;
using
PcapDotNet.Packets.Transport
;
namespace
PcapDotNet.Packets.Ip
{
/// <summary>
/// RFCs 791, 2460.
/// Represents an IP datagram.
/// <pre>
/// +-----+---------+
/// | Bit | 0-3 |
/// +-----+---------+
/// | 0 | Version |
/// +-----+---------+
/// | 4 | |
/// | ... | |
/// +-----+---------+
/// </pre>
/// </summary>
public
abstract
class
IpDatagram
:
Datagram
{
private
static
class
Offset
{
public
const
int
Version
=
0
;
}
private
static
class
Mask
{
public
const
byte
Version
=
0xF0
;
}
private
static
class
Shift
{
public
const
int
Version
=
4
;
}
/// <summary>
/// Indicates the format of the internet header (Internet Protocol version).
/// </summary>
public
byte
Version
{
get
{
return
(
byte
)((
this
[
Offset
.
Version
]
&
Mask
.
Version
)
>>
Shift
.
Version
);
}
}
public
abstract
int
TotalLength
{
get
;
}
/// <summary>
/// Returns whether the TCP or UDP checksum is correct.
/// The protocol must be TCP or UDP.
/// For UDP, the checksum is optional, so 0 checksum is still correct.
/// </summary>
public
bool
IsTransportChecksumCorrect
{
get
{
if
(
_isTransportChecksumCorrect
==
null
)
{
ushort
transportChecksum
=
Transport
.
Checksum
;
_isTransportChecksumCorrect
=
Length
>=
TotalLength
&&
(
Transport
.
IsChecksumOptional
&&
transportChecksum
==
0
)
||
(
CalculateTransportChecksum
()
==
transportChecksum
);
}
return
_isTransportChecksumCorrect
.
Value
;
}
}
/// <summary>
/// The payload of the datagram.
/// </summary>
public
Datagram
Payload
{
get
{
if
(
_payload
==
null
)
{
DataSegment
payload
=
GetPayload
();
if
(
payload
!=
null
)
_payload
=
new
Datagram
(
payload
.
Buffer
,
payload
.
StartOffset
,
payload
.
Length
);
}
return
_payload
;
}
}
/// <summary>
/// The payload of the datagram as an IPv4 datagram (IP over IP).
/// </summary>
public
IpV4Datagram
IpV4
{
get
{
if
(
_ipV4
==
null
)
{
DataSegment
payload
=
GetPayload
();
if
(
payload
!=
null
)
_ipV4
=
new
IpV4Datagram
(
payload
.
Buffer
,
payload
.
StartOffset
,
payload
.
Length
);
}
return
_ipV4
;
}
}
/// <summary>
/// The payload of the datagram as an IPv6 datagram (IP over IP).
/// </summary>
public
IpV6Datagram
IpV6
{
get
{
if
(
_ipV6
==
null
)
{
DataSegment
payload
=
GetPayload
();
if
(
payload
!=
null
)
_ipV6
=
new
IpV6Datagram
(
payload
.
Buffer
,
payload
.
StartOffset
,
payload
.
Length
);
}
return
_ipV6
;
}
}
/// <summary>
/// The payload of the datagram as an ICMP datagram.
/// </summary>
public
IcmpDatagram
Icmp
{
get
{
if
(
_icmp
==
null
)
{
DataSegment
payload
=
GetPayload
();
if
(
payload
!=
null
)
_icmp
=
IcmpDatagram
.
CreateDatagram
(
payload
.
Buffer
,
payload
.
StartOffset
,
payload
.
Length
);
}
return
_icmp
;
}
}
/// <summary>
/// The payload of the datagram as an IGMP datagram.
/// </summary>
public
IgmpDatagram
Igmp
{
get
{
if
(
_igmp
==
null
)
{
DataSegment
payload
=
GetPayload
();
if
(
payload
!=
null
)
_igmp
=
new
IgmpDatagram
(
payload
.
Buffer
,
payload
.
StartOffset
,
payload
.
Length
);
}
return
_igmp
;
}
}
/// <summary>
/// The payload of the datagram as a TCP datagram.
/// </summary>
public
TcpDatagram
Tcp
{
get
{
if
(
_tcp
==
null
)
{
DataSegment
payload
=
GetPayload
();
if
(
payload
!=
null
)
_tcp
=
new
TcpDatagram
(
payload
.
Buffer
,
payload
.
StartOffset
,
payload
.
Length
);
}
return
_tcp
;
}
}
/// <summary>
/// The payload of the datagram as a GRE datagram.
/// </summary>
public
GreDatagram
Gre
{
get
{
if
(
_gre
==
null
)
{
DataSegment
payload
=
GetPayload
();
if
(
payload
!=
null
)
_gre
=
new
GreDatagram
(
payload
.
Buffer
,
payload
.
StartOffset
,
payload
.
Length
);
}
return
_gre
;
}
}
/// <summary>
/// The payload of the datagram as a UDP datagram.
/// </summary>
public
UdpDatagram
Udp
{
get
{
if
(
_udp
==
null
)
{
DataSegment
payload
=
GetPayload
();
if
(
payload
!=
null
)
_udp
=
new
UdpDatagram
(
payload
.
Buffer
,
payload
.
StartOffset
,
payload
.
Length
);
}
return
_udp
;
}
}
/// <summary>
/// Returns the Tranposrt Datagram.
/// This is either a TCP Datagram or a UDP Datagram (according to the payload protocol).
/// </summary>
public
TransportDatagram
Transport
{
get
{
switch
(
PayloadProtocol
)
{
case
IpV4Protocol
.
Tcp
:
return
Tcp
;
case
IpV4Protocol
.
Udp
:
return
Udp
;
default
:
return
null
;
}
}
}
protected
abstract
ushort
CalculateTransportChecksum
();
internal
IpDatagram
(
byte
[]
buffer
,
int
offset
,
int
length
)
:
base
(
buffer
,
offset
,
length
)
{
}
internal
abstract
IpV4Protocol
PayloadProtocol
{
get
;
}
internal
abstract
DataSegment
GetPayload
();
private
bool
?
_isTransportChecksumCorrect
;
private
Datagram
_payload
;
private
IpV4Datagram
_ipV4
;
private
IpV6Datagram
_ipV6
;
private
IcmpDatagram
_icmp
;
private
IgmpDatagram
_igmp
;
private
GreDatagram
_gre
;
private
TcpDatagram
_tcp
;
private
UdpDatagram
_udp
;
}
}
\ No newline at end of file
PcapDotNet/src/PcapDotNet.Packets/IpV4/IpV4Datagram.cs
View file @
343e7103
...
...
@@ -4,13 +4,14 @@ using System.Linq;
using
PcapDotNet.Packets.Gre
;
using
PcapDotNet.Packets.Icmp
;
using
PcapDotNet.Packets.Igmp
;
using
PcapDotNet.Packets.Ip
;
using
PcapDotNet.Packets.Transport
;
namespace
PcapDotNet.Packets.IpV4
{
/// <summary>
/// RFC 791.
/// Represents an IPv4 datagram.
///
/// <pre>
/// +-----+---------+-----+-----------------+-------+-----------------+
/// | Bit | 0-3 | 4-7 | 8-15 | 16-18 | 19-31 |
...
...
@@ -33,7 +34,7 @@ namespace PcapDotNet.Packets.IpV4
/// +-----+-----------------------------------------------------------+
/// </pre>
/// </summary>
public
sealed
class
IpV4Datagram
:
Datagram
public
sealed
class
IpV4Datagram
:
Ip
Datagram
{
/// <summary>
/// The minimum length of the header in bytes.
...
...
@@ -63,15 +64,7 @@ namespace PcapDotNet.Packets.IpV4
/// <summary>
/// The version (4).
/// </summary>
public
const
int
DefaultVersion
=
0x4
;
/// <summary>
/// Indicates the format of the internet header.
/// </summary>
public
int
Version
{
get
{
return
(
this
[
Offset
.
VersionAndHeaderLength
]
&
0xF0
)
>>
4
;
}
}
public
const
byte
DefaultVersion
=
0x4
;
/// <summary>
/// The header length in bytes.
...
...
@@ -100,7 +93,7 @@ namespace PcapDotNet.Packets.IpV4
/// <summary>
/// The length of the entire datagram as stated in the total length field.
/// </summary>
public
ushor
t
TotalLength
public
override
in
t
TotalLength
{
get
{
return
ReadUShort
(
Offset
.
TotalLength
,
Endianity
.
Big
);
}
}
...
...
@@ -204,26 +197,6 @@ namespace PcapDotNet.Packets.IpV4
}
}
/// <summary>
/// Returns whether the TCP or UDP checksum is correct.
/// The protocol must be TCP or UDP.
/// For UDP, the checksum is optional, so 0 checksum is still correct.
/// </summary>
public
bool
IsTransportChecksumCorrect
{
get
{
if
(
_isTransportChecksumCorrect
==
null
)
{
ushort
transportChecksum
=
Transport
.
Checksum
;
_isTransportChecksumCorrect
=
Length
>=
TotalLength
&&
(
Transport
.
IsChecksumOptional
&&
transportChecksum
==
0
)
||
(
CalculateTransportChecksum
()
==
transportChecksum
);
}
return
_isTransportChecksumCorrect
.
Value
;
}
}
/// <summary>
/// Creates a Layer that represents the datagram to be used with PacketBuilder.
/// </summary>
...
...
@@ -243,122 +216,16 @@ namespace PcapDotNet.Packets.IpV4
};
}
/// <summary>
/// The payload of the datagram.
/// </summary>
public
Datagram
Payload
{
get
{
if
(
_payload
==
null
&&
Length
>=
HeaderLength
)
_payload
=
new
Datagram
(
Buffer
,
StartOffset
+
HeaderLength
,
Length
-
HeaderLength
);
return
_payload
;
}
}
/// <summary>
/// The payload of the datagram as an IPv4 datagram (IP over IP).
/// </summary>
public
IpV4Datagram
IpV4
{
get
{
if
(
_ipV4
==
null
&&
Length
>=
HeaderLength
)
_ipV4
=
new
IpV4Datagram
(
Buffer
,
StartOffset
+
HeaderLength
,
Length
-
HeaderLength
);
return
_ipV4
;
}
}
/// <summary>
/// The payload of the datagram as an ICMP datagram.
/// </summary>
public
IcmpDatagram
Icmp
{
get
{
if
(
_icmp
==
null
&&
Length
>=
HeaderMinimumLength
&&
Length
>=
HeaderLength
)
_icmp
=
IcmpDatagram
.
CreateDatagram
(
Buffer
,
StartOffset
+
HeaderLength
,
Length
-
HeaderLength
);
return
_icmp
;
}
}
/// <summary>
/// The payload of the datagram as an IGMP datagram.
/// </summary>
public
IgmpDatagram
Igmp
{
get
{
if
(
_igmp
==
null
&&
Length
>=
HeaderMinimumLength
&&
Length
>=
HeaderLength
)
_igmp
=
new
IgmpDatagram
(
Buffer
,
StartOffset
+
HeaderLength
,
Length
-
HeaderLength
);
return
_igmp
;
}
}
/// <summary>
/// The payload of the datagram as a TCP datagram.
/// </summary>
public
TcpDatagram
Tcp
{
get
{
if
(
_tcp
==
null
&&
Length
>=
HeaderMinimumLength
&&
Length
>=
HeaderLength
)
_tcp
=
new
TcpDatagram
(
Buffer
,
StartOffset
+
HeaderLength
,
Length
-
HeaderLength
);
return
_tcp
;
}
}
/// <summary>
/// The payload of the datagram as a GRE datagram.
/// </summary>
public
GreDatagram
Gre
internal
override
IpV4Protocol
PayloadProtocol
{
get
{
if
(
_gre
==
null
&&
Length
>=
HeaderMinimumLength
&&
Length
>=
HeaderLength
)
_gre
=
new
GreDatagram
(
Buffer
,
StartOffset
+
HeaderLength
,
Length
-
HeaderLength
);
return
_gre
;
}
get
{
return
Protocol
;
}
}
/// <summary>
/// The payload of the datagram as a UDP datagram.
/// </summary>
public
UdpDatagram
Udp
internal
override
DataSegment
GetPayload
()
{
get
{
if
(
_udp
==
null
&&
Length
>=
HeaderMinimumLength
&&
Length
>=
HeaderLength
)
_udp
=
new
UdpDatagram
(
Buffer
,
StartOffset
+
HeaderLength
,
Length
-
HeaderLength
);
return
_udp
;
}
}
/// <summary>
/// Returns the Tranposrt Datagram.
/// This is either a TCP Datagram or a UDP Datagram (according to the protocol).
/// </summary>
public
TransportDatagram
Transport
{
get
{
switch
(
Protocol
)
{
case
IpV4Protocol
.
Tcp
:
return
Tcp
;
case
IpV4Protocol
.
Udp
:
return
Udp
;
default
:
return
null
;
}
}
if
(
Length
<
HeaderMinimumLength
||
Length
<
HeaderLength
)
return
null
;
return
Subsegment
(
HeaderLength
,
Length
-
HeaderLength
);
}
internal
static
int
GetTotalLength
(
Datagram
ipV4Datagram
)
...
...
@@ -466,6 +333,11 @@ namespace PcapDotNet.Packets.IpV4
}
}
protected
override
ushort
CalculateTransportChecksum
()
{
return
CalculateTransportChecksum
(
Buffer
,
StartOffset
,
HeaderLength
,
(
ushort
)
Transport
.
Length
,
Transport
.
ChecksumOffset
,
Transport
.
IsChecksumOptional
,
Destination
);
}
private
ushort
CalculateHeaderChecksum
()
{
uint
sum
=
Sum16Bits
(
Buffer
,
StartOffset
,
Math
.
Min
(
Offset
.
HeaderChecksum
,
Length
))
+
...
...
@@ -474,11 +346,6 @@ namespace PcapDotNet.Packets.IpV4
return
Sum16BitsToChecksum
(
sum
);
}
private
ushort
CalculateTransportChecksum
()
{
return
CalculateTransportChecksum
(
Buffer
,
StartOffset
,
HeaderLength
,
(
ushort
)
Transport
.
Length
,
Transport
.
ChecksumOffset
,
Transport
.
IsChecksumOptional
,
Destination
);
}
private
static
ushort
CalculateTransportChecksum
(
byte
[]
buffer
,
int
offset
,
int
headerLength
,
ushort
transportLength
,
int
transportChecksumOffset
,
bool
isChecksumOptional
,
IpV4Address
destination
)
{
int
offsetAfterChecksum
=
offset
+
headerLength
+
transportChecksumOffset
+
2
;
...
...
@@ -496,14 +363,6 @@ namespace PcapDotNet.Packets.IpV4
private
IpV4Address
?
_destination
;
private
bool
?
_isHeaderChecksumCorrect
;
private
bool
?
_isTransportChecksumCorrect
;
private
IpV4Options
_options
;
private
Datagram
_payload
;
private
IpV4Datagram
_ipV4
;
private
IcmpDatagram
_icmp
;
private
IgmpDatagram
_igmp
;
private
GreDatagram
_gre
;
private
TcpDatagram
_tcp
;
private
UdpDatagram
_udp
;
}
}
\ No newline at end of file
PcapDotNet/src/PcapDotNet.Packets/IpV6/ExtensionHeaders/IpV6ExtensionHeader.cs
View file @
343e7103
...
...
@@ -98,30 +98,6 @@ namespace PcapDotNet.Packets.IpV6
}
}
internal
static
void
GetNextNextHeaderAndLength
(
IpV4Protocol
nextHeader
,
DataSegment
data
,
out
IpV4Protocol
?
nextNextHeader
,
out
int
extensionHeaderLength
)
{
if
(
IpV6ExtensionHeaderStandard
.
IsStandard
(
nextHeader
))
{
IpV6ExtensionHeaderStandard
.
GetNextNextHeaderAndLength
(
data
,
out
nextNextHeader
,
out
extensionHeaderLength
);
return
;
}
switch
(
nextHeader
)
{
case
IpV4Protocol
.
EncapsulatingSecurityPayload
:
// 50
IpV6ExtensionHeaderEncapsulatingSecurityPayload
.
GetNextNextHeaderAndLength
(
data
,
out
nextNextHeader
,
out
extensionHeaderLength
);
break
;
case
IpV4Protocol
.
AuthenticationHeader
:
// 51
IpV6ExtensionHeaderAuthentication
.
GetNextNextHeaderAndLength
(
data
,
out
nextNextHeader
,
out
extensionHeaderLength
);
break
;
default
:
throw
new
InvalidOperationException
(
string
.
Format
(
CultureInfo
.
InvariantCulture
,
"Invalid next header value {0}"
,
nextHeader
));
}
}
internal
abstract
void
Write
(
byte
[]
buffer
,
ref
int
offset
);
private
static
readonly
ReadOnlyCollection
<
IpV4Protocol
>
_extensionHeaders
=
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV6/ExtensionHeaders/IpV6ExtensionHeaderAuthentication.cs
View file @
343e7103
...
...
@@ -200,19 +200,6 @@ namespace PcapDotNet.Packets.IpV6
return
new
IpV6ExtensionHeaderAuthentication
(
nextHeader
,
securityParametersIndex
,
sequenceNumber
,
authenticationData
);
}
internal
static
void
GetNextNextHeaderAndLength
(
DataSegment
extensionHeader
,
out
IpV4Protocol
?
nextNextHeader
,
out
int
extensionHeaderLength
)
{
if
(
extensionHeader
.
Length
<
MinimumLength
)
{
nextNextHeader
=
null
;
extensionHeaderLength
=
extensionHeader
.
Length
;
return
;
}
nextNextHeader
=
(
IpV4Protocol
)
extensionHeader
[
Offset
.
NextHeader
];
extensionHeaderLength
=
(
extensionHeader
[
Offset
.
PayloadLength
]
+
2
)
*
4
;
}
internal
override
void
Write
(
byte
[]
buffer
,
ref
int
offset
)
{
buffer
.
Write
(
offset
+
Offset
.
NextHeader
,
(
byte
)
NextHeader
);
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV6/ExtensionHeaders/IpV6ExtensionHeaderEncapsulatingSecurityPayload.cs
View file @
343e7103
...
...
@@ -209,12 +209,6 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public
DataSegment
EncryptedDataAndAuthenticationData
{
get
;
private
set
;
}
internal
static
void
GetNextNextHeaderAndLength
(
DataSegment
extensionHeader
,
out
IpV4Protocol
?
nextNextHeader
,
out
int
extensionHeaderLength
)
{
nextNextHeader
=
null
;
extensionHeaderLength
=
extensionHeader
.
Length
;
}
internal
static
IpV6ExtensionHeaderEncapsulatingSecurityPayload
CreateInstance
(
DataSegment
extensionHeaderData
,
out
int
numBytesRead
)
{
if
(
extensionHeaderData
.
Length
<
MinimumLength
)
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV6/ExtensionHeaders/IpV6ExtensionHeaderStandard.cs
View file @
343e7103
...
...
@@ -128,18 +128,6 @@ namespace PcapDotNet.Packets.IpV6
}
}
internal
static
void
GetNextNextHeaderAndLength
(
DataSegment
extensionHeader
,
out
IpV4Protocol
?
nextNextHeader
,
out
int
extensionHeaderLength
)
{
if
(
extensionHeader
.
Length
<
MinimumLength
)
{
nextNextHeader
=
null
;
extensionHeaderLength
=
extensionHeader
.
Length
;
return
;
}
nextNextHeader
=
(
IpV4Protocol
)
extensionHeader
[
Offset
.
NextHeader
];
extensionHeaderLength
=
Math
.
Min
(
extensionHeader
.
Length
/
8
*
8
,
(
extensionHeader
[
Offset
.
HeaderExtensionLength
]
+
1
)
*
8
);
}
internal
static
ReadOnlyCollection
<
IpV4Protocol
>
StandardExtensionHeaders
{
get
{
return
_standardExtensionHeaders
;
}
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV6/ExtensionHeaders/IpV6ExtensionHeaders.cs
View file @
343e7103
...
...
@@ -110,6 +110,8 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public
ReadOnlyCollection
<
IpV6ExtensionHeader
>
Headers
{
get
;
private
set
;
}
public
int
BytesLength
{
get
;
private
set
;
}
/// <summary>
/// True iff a parsing issue wasn't encountered when parsing the extension headers.
/// </summary>
...
...
@@ -188,6 +190,7 @@ namespace PcapDotNet.Packets.IpV6
internal
IpV6ExtensionHeaders
(
DataSegment
data
,
IpV4Protocol
firstHeader
)
{
BytesLength
=
0
;
IpV4Protocol
?
nextHeader
=
firstHeader
;
List
<
IpV6ExtensionHeader
>
headers
=
new
List
<
IpV6ExtensionHeader
>();
while
(
data
.
Length
>=
8
&&
nextHeader
.
HasValue
&&
IpV6ExtensionHeader
.
IsExtensionHeader
(
nextHeader
.
Value
))
...
...
@@ -196,6 +199,7 @@ namespace PcapDotNet.Packets.IpV6
IpV6ExtensionHeader
extensionHeader
=
IpV6ExtensionHeader
.
CreateInstance
(
nextHeader
.
Value
,
data
,
out
numBytesRead
);
if
(
extensionHeader
==
null
)
break
;
BytesLength
+=
numBytesRead
;
headers
.
Add
(
extensionHeader
);
nextHeader
=
extensionHeader
.
NextHeader
;
data
=
data
.
Subsegment
(
numBytesRead
,
data
.
Length
-
numBytesRead
);
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV6/IpV6Datagram.cs
View file @
343e7103
...
...
@@ -2,6 +2,7 @@ using System;
using
System.Collections.Generic
;
using
System.Collections.ObjectModel
;
using
PcapDotNet.Base
;
using
PcapDotNet.Packets.Ip
;
using
PcapDotNet.Packets.IpV4
;
namespace
PcapDotNet.Packets.IpV6
...
...
@@ -32,7 +33,7 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+-----------------------------------------------------------+
/// </pre>
/// </summary>
public
sealed
class
IpV6Datagram
:
Datagram
public
sealed
class
IpV6Datagram
:
Ip
Datagram
{
/// <summary>
/// The number of bytes the header takes in bytes (not including extension headers).
...
...
@@ -74,14 +75,6 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public
const
int
DefaultVersion
=
0x6
;
/// <summary>
/// Internet Protocol version number.
/// </summary>
public
byte
Version
{
get
{
return
(
byte
)((
this
[
Offset
.
Version
]
&
Mask
.
Version
)
>>
Shift
.
Version
);
}
}
/// <summary>
/// Available for use by originating nodes and/or forwarding routers to identify and distinguish between different classes or priorities of
/// IPv6 packets.
...
...
@@ -170,6 +163,49 @@ namespace PcapDotNet.Packets.IpV6
}
}
public
override
int
TotalLength
{
get
{
return
HeaderLength
+
PayloadLength
;
}
}
protected
override
ushort
CalculateTransportChecksum
()
{
return
CalculateTransportChecksum
(
Buffer
,
StartOffset
,
(
ushort
)
Transport
.
Length
,
Transport
.
ChecksumOffset
,
Transport
.
IsChecksumOptional
,
CurrentDestination
);
}
private
static
ushort
CalculateTransportChecksum
(
byte
[]
buffer
,
int
offset
,
ushort
transportLength
,
int
transportChecksumOffset
,
bool
isChecksumOptional
,
IpV6Address
destination
)
{
int
offsetAfterChecksum
=
offset
+
HeaderLength
+
transportChecksumOffset
+
2
;
uint
sum
=
Sum16Bits
(
buffer
,
offset
+
Offset
.
SourceAddress
,
IpV6Address
.
SizeOf
)
+
Sum16Bits
(
destination
)
+
transportLength
+
buffer
[
offset
+
Offset
.
NextHeader
]
+
Sum16Bits
(
buffer
,
offset
+
HeaderLength
,
transportChecksumOffset
)
+
Sum16Bits
(
buffer
,
offsetAfterChecksum
,
transportLength
-
transportChecksumOffset
-
2
);
ushort
checksumResult
=
Sum16BitsToChecksum
(
sum
);
if
(
checksumResult
==
0
&&
isChecksumOptional
)
return
0xFFFF
;
return
checksumResult
;
}
internal
override
IpV4Protocol
PayloadProtocol
{
get
{
IpV4Protocol
?
extensionHeadersNextHeader
=
ExtensionHeaders
.
NextHeader
;
if
(
extensionHeadersNextHeader
!=
null
)
return
extensionHeadersNextHeader
.
Value
;
return
NextHeader
;
}
}
internal
override
DataSegment
GetPayload
()
{
if
(
Length
<
HeaderLength
)
return
null
;
return
Subsegment
(
HeaderLength
+
ExtensionHeaders
.
BytesLength
,
Length
-
HeaderLength
-
ExtensionHeaders
.
BytesLength
);
}
private
void
ParseExtensionHeaders
()
{
if
(
_extensionHeaders
!=
null
)
...
...
@@ -221,16 +257,7 @@ namespace PcapDotNet.Packets.IpV6
if
(
payload
.
Length
<=
HeaderLength
)
return
payload
.
Length
;
int
totalLength
=
HeaderLength
;
IpV4Protocol
?
nextHeader
=
(
IpV4Protocol
)
payload
[
Offset
.
NextHeader
];
while
(
nextHeader
.
HasValue
&&
IpV6ExtensionHeader
.
IsExtensionHeader
(
nextHeader
.
Value
))
{
int
extensionHeaderLength
;
IpV6ExtensionHeader
.
GetNextNextHeaderAndLength
(
nextHeader
.
Value
,
payload
.
Subsegment
(
totalLength
,
payload
.
Length
-
totalLength
),
out
nextHeader
,
out
extensionHeaderLength
);
totalLength
+=
extensionHeaderLength
;
}
return
totalLength
;
return
Math
.
Min
(
payload
.
Length
,
HeaderLength
+
payload
.
ReadUShort
(
Offset
.
PayloadLength
,
Endianity
.
Big
));
}
internal
static
void
WriteHeader
(
byte
[]
buffer
,
int
offset
,
...
...
PcapDotNet/src/PcapDotNet.Packets/PcapDotNet.Packets.csproj
View file @
343e7103
...
...
@@ -316,6 +316,7 @@
<Compile
Include=
"Igmp\IgmpRecordType.cs"
/>
<Compile
Include=
"Igmp\IgmpMessageType.cs"
/>
<Compile
Include=
"Igmp\IIgmpLayerWithGroupAddress.cs"
/>
<Compile
Include=
"Ip\IpDatagram.cs"
/>
<Compile
Include=
"IpV6\IpV6BindingAcknowledgementStatus.cs"
/>
<Compile
Include=
"IpV6\ExtensionHeaders\IpV6BindingErrorStatus.cs"
/>
<Compile
Include=
"IpV6\ExtensionHeaders\IpV6ExtensionHeaderMobility.cs"
/>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment