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
ca31c6f5
Commit
ca31c6f5
authored
Aug 08, 2009
by
Brickner_cp
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
IpV4OptionComplex refactoring.
parent
3d7eb78d
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
163 additions
and
70 deletions
+163
-70
IpV4OptionBasicSecurity.cs
...et/src/PcapDotNet.Packets/IpV4/IpV4OptionBasicSecurity.cs
+23
-2
IpV4OptionComplex.cs
PcapDotNet/src/PcapDotNet.Packets/IpV4/IpV4OptionComplex.cs
+50
-27
IpV4OptionLooseSourceRouting.cs
...c/PcapDotNet.Packets/IpV4/IpV4OptionLooseSourceRouting.cs
+11
-2
IpV4OptionRecordRoute.cs
...tNet/src/PcapDotNet.Packets/IpV4/IpV4OptionRecordRoute.cs
+11
-2
IpV4OptionStreamIdentifier.cs
...src/PcapDotNet.Packets/IpV4/IpV4OptionStreamIdentifier.cs
+11
-2
IpV4OptionStrictSourceRouting.cs
.../PcapDotNet.Packets/IpV4/IpV4OptionStrictSourceRouting.cs
+11
-2
IpV4OptionTimestamp.cs
...DotNet/src/PcapDotNet.Packets/IpV4/IpV4OptionTimestamp.cs
+35
-31
IpV4OptionTraceRoute.cs
...otNet/src/PcapDotNet.Packets/IpV4/IpV4OptionTraceRoute.cs
+11
-2
No files found.
PcapDotNet/src/PcapDotNet.Packets/IpV4/IpV4OptionBasicSecurity.cs
View file @
ca31c6f5
...
@@ -31,7 +31,8 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -31,7 +31,8 @@ namespace PcapDotNet.Packets.IpV4
/// LEVEL AUTHORITY
/// LEVEL AUTHORITY
/// FLAGS
/// FLAGS
/// </summary>
/// </summary>
public
class
IpV4OptionBasicSecurity
:
IpV4OptionComplex
,
IEquatable
<
IpV4OptionBasicSecurity
>
[
IpV4OptionTypeRegistration
(
IpV4OptionType
.
BasicSecurity
)]
public
class
IpV4OptionBasicSecurity
:
IpV4OptionComplex
,
IIpv4OptionComplexFactory
,
IEquatable
<
IpV4OptionBasicSecurity
>
{
{
/// <summary>
/// <summary>
/// The minimum number of bytes this option take.
/// The minimum number of bytes this option take.
...
@@ -74,6 +75,26 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -74,6 +75,26 @@ namespace PcapDotNet.Packets.IpV4
_length
=
length
;
_length
=
length
;
}
}
/// <summary>
/// Create the security option with only classification level.
/// </summary>
/// <param name="classificationLevel">
/// This field specifies the (U.S.) classification level at which the datagram must be protected.
/// The information in the datagram must be protected at this level.
/// </param>
public
IpV4OptionBasicSecurity
(
IpV4OptionSecurityClassificationLevel
classificationLevel
)
:
this
(
classificationLevel
,
IpV4OptionSecurityProtectionAuthority
.
None
,
OptionMinimumLength
)
{
}
/// <summary>
/// Creates unclassified security option.
/// </summary>
public
IpV4OptionBasicSecurity
()
:
this
(
IpV4OptionSecurityClassificationLevel
.
Unclassified
)
{
}
/// <summary>
/// <summary>
/// This field specifies the (U.S.) classification level at which the datagram must be protected.
/// This field specifies the (U.S.) classification level at which the datagram must be protected.
/// The information in the datagram must be protected at this level.
/// The information in the datagram must be protected at this level.
...
@@ -141,7 +162,7 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -141,7 +162,7 @@ namespace PcapDotNet.Packets.IpV4
((((
byte
)
ClassificationLevel
)
<<
16
)
|
(((
byte
)
ProtectionAuthority
)
<<
8
)
|
Length
).
GetHashCode
();
((((
byte
)
ClassificationLevel
)
<<
16
)
|
(((
byte
)
ProtectionAuthority
)
<<
8
)
|
Length
).
GetHashCode
();
}
}
internal
static
IpV4OptionBasicSecurity
ReadOptionSecurity
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
public
IpV4OptionComplex
CreateInstance
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
{
{
if
(
valueLength
<
OptionValueMinimumLength
)
if
(
valueLength
<
OptionValueMinimumLength
)
return
null
;
return
null
;
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV4/IpV4OptionComplex.cs
View file @
ca31c6f5
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Reflection
;
namespace
PcapDotNet.Packets.IpV4
namespace
PcapDotNet.Packets.IpV4
{
{
internal
class
IpV4OptionTypeRegistrationAttribute
:
Attribute
{
public
IpV4OptionTypeRegistrationAttribute
(
IpV4OptionType
optionType
)
{
OptionType
=
optionType
;
}
public
IpV4OptionType
OptionType
{
get
;
set
;
}
}
internal
interface
IIpv4OptionComplexFactory
{
IpV4OptionComplex
CreateInstance
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
);
}
/// <summary>
/// <summary>
/// Represents a complex IPv4 option.
/// Represents a complex IPv4 option.
/// Complex option means that it contains data and not just the type.
/// Complex option means that it contains data and not just the type.
/// </summary>
/// </summary>
public
abstract
class
IpV4OptionComplex
:
IpV4Option
public
abstract
class
IpV4OptionComplex
:
IpV4Option
{
{
private
static
readonly
Dictionary
<
IpV4OptionType
,
IIpv4OptionComplexFactory
>
_complexOptions
;
static
IpV4OptionComplex
()
{
var
complexOptions
=
from
type
in
Assembly
.
GetExecutingAssembly
().
GetTypes
()
where
typeof
(
IIpv4OptionComplexFactory
).
IsAssignableFrom
(
type
)
&&
GetRegistrationAttribute
(
type
)
!=
null
select
new
{
GetRegistrationAttribute
(
type
).
OptionType
,
Option
=
(
IIpv4OptionComplexFactory
)
Activator
.
CreateInstance
(
type
)
};
_complexOptions
=
complexOptions
.
ToDictionary
(
option
=>
option
.
OptionType
,
option
=>
option
.
Option
);
}
private
static
IpV4OptionTypeRegistrationAttribute
GetRegistrationAttribute
(
Type
type
)
{
var
registraionAttributes
=
type
.
GetCustomAttributes
(
typeof
(
IpV4OptionTypeRegistrationAttribute
),
false
);
if
(
registraionAttributes
.
Length
==
0
)
return
null
;
return
((
IpV4OptionTypeRegistrationAttribute
)
registraionAttributes
[
0
]);
}
/// <summary>
/// <summary>
/// The header length in bytes for the option (type and size).
/// The header length in bytes for the option (type and size).
/// </summary>
/// </summary>
...
@@ -18,36 +64,13 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -18,36 +64,13 @@ namespace PcapDotNet.Packets.IpV4
byte
optionLength
=
buffer
[
offset
++];
byte
optionLength
=
buffer
[
offset
++];
if
(
length
+
1
<
optionLength
)
if
(
length
+
1
<
optionLength
)
return
null
;
return
null
;
byte
optionValueLength
=
(
byte
)(
optionLength
-
OptionHeaderLength
);
byte
optionValueLength
=
(
byte
)(
optionLength
-
OptionHeaderLength
);
switch
(
optionType
)
IIpv4OptionComplexFactory
prototype
;
{
if
(!
_complexOptions
.
TryGetValue
(
optionType
,
out
prototype
))
case
IpV4OptionType
.
BasicSecurity
:
return
null
;
return
IpV4OptionBasicSecurity
.
ReadOptionSecurity
(
buffer
,
ref
offset
,
optionValueLength
);
case
IpV4OptionType
.
LooseSourceRouting
:
return
IpV4OptionLooseSourceRouting
.
ReadOptionLooseSourceRouting
(
buffer
,
ref
offset
,
optionValueLength
);
case
IpV4OptionType
.
StrictSourceRouting
:
return
IpV4OptionStrictSourceRouting
.
ReadOptionStrictSourceRouting
(
buffer
,
ref
offset
,
optionValueLength
);
case
IpV4OptionType
.
RecordRoute
:
return
IpV4OptionRecordRoute
.
ReadOptionRecordRoute
(
buffer
,
ref
offset
,
optionValueLength
);
case
IpV4OptionType
.
StreamIdentifier
:
return
IpV4OptionStreamIdentifier
.
ReadOptionStreamIdentifier
(
buffer
,
ref
offset
,
optionValueLength
);
case
IpV4OptionType
.
InternetTimestamp
:
return
IpV4OptionTimestamp
.
ReadOptionTimestamp
(
buffer
,
ref
offset
,
optionValueLength
);
case
IpV4OptionType
.
TraceRoute
:
return
IpV4OptionTraceRoute
.
ReadOptionTraceRoute
(
buffer
,
ref
offset
,
optionValueLength
);
default
:
return
null
;
}
return
prototype
.
CreateInstance
(
buffer
,
ref
offset
,
optionValueLength
);
}
}
internal
override
void
Write
(
byte
[]
buffer
,
ref
int
offset
)
internal
override
void
Write
(
byte
[]
buffer
,
ref
int
offset
)
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV4/IpV4OptionLooseSourceRouting.cs
View file @
ca31c6f5
...
@@ -42,7 +42,8 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -42,7 +42,8 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation.
/// Must be copied on fragmentation.
/// Appears at most once in a datagram.
/// Appears at most once in a datagram.
/// </summary>
/// </summary>
public
class
IpV4OptionLooseSourceRouting
:
IpV4OptionRoute
[
IpV4OptionTypeRegistration
(
IpV4OptionType
.
LooseSourceRouting
)]
public
class
IpV4OptionLooseSourceRouting
:
IpV4OptionRoute
,
IIpv4OptionComplexFactory
{
{
/// <summary>
/// <summary>
/// Constructs the option from the given values.
/// Constructs the option from the given values.
...
@@ -54,7 +55,15 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -54,7 +55,15 @@ namespace PcapDotNet.Packets.IpV4
{
{
}
}
internal
static
IpV4OptionLooseSourceRouting
ReadOptionLooseSourceRouting
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
/// <summary>
/// Empty loose source routing.
/// </summary>
public
IpV4OptionLooseSourceRouting
()
:
this
(
new
IpV4Address
[]{},
0
)
{
}
public
IpV4OptionComplex
CreateInstance
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
{
{
IpV4Address
[]
addresses
;
IpV4Address
[]
addresses
;
byte
pointedAddressIndex
;
byte
pointedAddressIndex
;
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV4/IpV4OptionRecordRoute.cs
View file @
ca31c6f5
...
@@ -39,7 +39,8 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -39,7 +39,8 @@ namespace PcapDotNet.Packets.IpV4
/// Not copied on fragmentation, goes in first fragment only.
/// Not copied on fragmentation, goes in first fragment only.
/// Appears at most once in a datagram.
/// Appears at most once in a datagram.
/// </summary>
/// </summary>
public
class
IpV4OptionRecordRoute
:
IpV4OptionRoute
[
IpV4OptionTypeRegistration
(
IpV4OptionType
.
RecordRoute
)]
public
class
IpV4OptionRecordRoute
:
IpV4OptionRoute
,
IIpv4OptionComplexFactory
{
{
/// <summary>
/// <summary>
/// Constructs the option from the given values.
/// Constructs the option from the given values.
...
@@ -61,7 +62,15 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -61,7 +62,15 @@ namespace PcapDotNet.Packets.IpV4
{
{
}
}
internal
static
IpV4OptionRecordRoute
ReadOptionRecordRoute
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
/// <summary>
/// Constructs an empty record route option.
/// </summary>
public
IpV4OptionRecordRoute
()
:
this
(
0
)
{
}
public
IpV4OptionComplex
CreateInstance
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
{
{
IpV4Address
[]
addresses
;
IpV4Address
[]
addresses
;
byte
pointedAddressIndex
;
byte
pointedAddressIndex
;
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV4/IpV4OptionStreamIdentifier.cs
View file @
ca31c6f5
...
@@ -14,7 +14,8 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -14,7 +14,8 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation.
/// Must be copied on fragmentation.
/// Appears at most once in a datagram.
/// Appears at most once in a datagram.
/// </summary>
/// </summary>
public
class
IpV4OptionStreamIdentifier
:
IpV4OptionComplex
,
IEquatable
<
IpV4OptionStreamIdentifier
>
[
IpV4OptionTypeRegistration
(
IpV4OptionType
.
StreamIdentifier
)]
public
class
IpV4OptionStreamIdentifier
:
IpV4OptionComplex
,
IIpv4OptionComplexFactory
,
IEquatable
<
IpV4OptionStreamIdentifier
>
{
{
/// <summary>
/// <summary>
/// The number of bytes this option take.
/// The number of bytes this option take.
...
@@ -87,7 +88,15 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -87,7 +88,15 @@ namespace PcapDotNet.Packets.IpV4
Identifier
.
GetHashCode
();
Identifier
.
GetHashCode
();
}
}
internal
static
IpV4OptionStreamIdentifier
ReadOptionStreamIdentifier
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
/// <summary>
/// Creates a 0 stream identifier
/// </summary>
public
IpV4OptionStreamIdentifier
()
:
this
(
0
)
{
}
public
IpV4OptionComplex
CreateInstance
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
{
{
if
(
valueLength
!=
OptionHeaderLength
)
if
(
valueLength
!=
OptionHeaderLength
)
return
null
;
return
null
;
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV4/IpV4OptionStrictSourceRouting.cs
View file @
ca31c6f5
...
@@ -43,7 +43,8 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -43,7 +43,8 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation.
/// Must be copied on fragmentation.
/// Appears at most once in a datagram.
/// Appears at most once in a datagram.
/// </summary>
/// </summary>
public
class
IpV4OptionStrictSourceRouting
:
IpV4OptionRoute
[
IpV4OptionTypeRegistration
(
IpV4OptionType
.
StrictSourceRouting
)]
public
class
IpV4OptionStrictSourceRouting
:
IpV4OptionRoute
,
IIpv4OptionComplexFactory
{
{
/// <summary>
/// <summary>
/// Create the option according to the given values.
/// Create the option according to the given values.
...
@@ -53,7 +54,15 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -53,7 +54,15 @@ namespace PcapDotNet.Packets.IpV4
{
{
}
}
internal
static
IpV4OptionStrictSourceRouting
ReadOptionStrictSourceRouting
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
/// <summary>
/// Creates an empty strict source routing option.
/// </summary>
public
IpV4OptionStrictSourceRouting
()
:
this
(
new
List
<
IpV4Address
>(),
0
)
{
}
public
IpV4OptionComplex
CreateInstance
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
{
{
IpV4Address
[]
addresses
;
IpV4Address
[]
addresses
;
byte
pointedAddressIndex
;
byte
pointedAddressIndex
;
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV4/IpV4OptionTimestamp.cs
View file @
ca31c6f5
...
@@ -52,6 +52,41 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -52,6 +52,41 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
/// </summary>
public
abstract
class
IpV4OptionTimestamp
:
IpV4OptionComplex
,
IEquatable
<
IpV4OptionTimestamp
>
public
abstract
class
IpV4OptionTimestamp
:
IpV4OptionComplex
,
IEquatable
<
IpV4OptionTimestamp
>
{
{
[
IpV4OptionTypeRegistration
(
IpV4OptionType
.
InternetTimestamp
)]
internal
class
IpV4OptionTimestampFactory
:
IIpv4OptionComplexFactory
{
public
IpV4OptionComplex
CreateInstance
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
{
if
(
valueLength
<
OptionValueMinimumLength
||
valueLength
%
4
!=
2
)
return
null
;
byte
pointer
=
buffer
[
offset
++];
if
(
pointer
%
4
!=
1
||
pointer
<
5
)
return
null
;
byte
pointedIndex
=
(
byte
)(
pointer
/
4
-
1
);
byte
overflow
=
buffer
[
offset
++];
IpV4OptionTimestampType
timestampType
=
(
IpV4OptionTimestampType
)(
overflow
&
0x0F
);
overflow
>>=
4
;
int
numValues
=
valueLength
/
4
;
switch
(
timestampType
)
{
case
IpV4OptionTimestampType
.
TimestampOnly
:
return
IpV4OptionTimestampOnly
.
Read
(
overflow
,
pointedIndex
,
buffer
,
ref
offset
,
numValues
);
case
IpV4OptionTimestampType
.
AddressAndTimestamp
:
case
IpV4OptionTimestampType
.
AddressPrespecified
:
return
IpV4OptionTimestampAndAddress
.
Read
(
timestampType
,
overflow
,
pointedIndex
,
buffer
,
ref
offset
,
numValues
);
default
:
return
null
;
}
}
}
/// <summary>
/// <summary>
/// The minimum length in bytes for the option (type, length, pointer, overflow and flags).
/// The minimum length in bytes for the option (type, length, pointer, overflow and flags).
/// </summary>
/// </summary>
...
@@ -154,37 +189,6 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -154,37 +189,6 @@ namespace PcapDotNet.Packets.IpV4
PointedIndex
.
GetHashCode
();
PointedIndex
.
GetHashCode
();
}
}
internal
static
IpV4OptionTimestamp
ReadOptionTimestamp
(
byte
[]
buffer
,
ref
int
offset
,
int
valueLength
)
{
if
(
valueLength
<
OptionValueMinimumLength
||
valueLength
%
4
!=
2
)
return
null
;
byte
pointer
=
buffer
[
offset
++];
if
(
pointer
%
4
!=
1
||
pointer
<
5
)
return
null
;
byte
pointedIndex
=
(
byte
)(
pointer
/
4
-
1
);
byte
overflow
=
buffer
[
offset
++];
IpV4OptionTimestampType
timestampType
=
(
IpV4OptionTimestampType
)(
overflow
&
0x0F
);
overflow
>>=
4
;
int
numValues
=
valueLength
/
4
;
switch
(
timestampType
)
{
case
IpV4OptionTimestampType
.
TimestampOnly
:
return
IpV4OptionTimestampOnly
.
Read
(
overflow
,
pointedIndex
,
buffer
,
ref
offset
,
numValues
);
case
IpV4OptionTimestampType
.
AddressAndTimestamp
:
case
IpV4OptionTimestampType
.
AddressPrespecified
:
return
IpV4OptionTimestampAndAddress
.
Read
(
timestampType
,
overflow
,
pointedIndex
,
buffer
,
ref
offset
,
numValues
);
default
:
return
null
;
}
}
internal
override
void
Write
(
byte
[]
buffer
,
ref
int
offset
)
internal
override
void
Write
(
byte
[]
buffer
,
ref
int
offset
)
{
{
base
.
Write
(
buffer
,
ref
offset
);
base
.
Write
(
buffer
,
ref
offset
);
...
...
PcapDotNet/src/PcapDotNet.Packets/IpV4/IpV4OptionTraceRoute.cs
View file @
ca31c6f5
...
@@ -24,7 +24,8 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -24,7 +24,8 @@ namespace PcapDotNet.Packets.IpV4
/// C (class): 2 (Debugging & Measurement)
/// C (class): 2 (Debugging & Measurement)
/// Number: 18 (F+C+Number = 82)
/// Number: 18 (F+C+Number = 82)
/// </summary>
/// </summary>
public
class
IpV4OptionTraceRoute
:
IpV4OptionComplex
,
IEquatable
<
IpV4OptionTraceRoute
>
[
IpV4OptionTypeRegistration
(
IpV4OptionType
.
TraceRoute
)]
public
class
IpV4OptionTraceRoute
:
IpV4OptionComplex
,
IIpv4OptionComplexFactory
,
IEquatable
<
IpV4OptionTraceRoute
>
{
{
/// <summary>
/// <summary>
/// The number of bytes this option take.
/// The number of bytes this option take.
...
@@ -66,6 +67,14 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -66,6 +67,14 @@ namespace PcapDotNet.Packets.IpV4
_originatorIpAddress
=
originatorIpAddress
;
_originatorIpAddress
=
originatorIpAddress
;
}
}
/// <summary>
/// Creates empty trace route option.
/// </summary>
public
IpV4OptionTraceRoute
()
:
this
(
0
,
0
,
0
,
IpV4Address
.
Zero
)
{
}
/// <summary>
/// <summary>
/// An arbitrary number used by the originator of the Outbound Packet to identify the ICMP Traceroute messages.
/// An arbitrary number used by the originator of the Outbound Packet to identify the ICMP Traceroute messages.
/// It is NOT related to the ID number in the IP header.
/// It is NOT related to the ID number in the IP header.
...
@@ -157,7 +166,7 @@ namespace PcapDotNet.Packets.IpV4
...
@@ -157,7 +166,7 @@ namespace PcapDotNet.Packets.IpV4
}
}
internal
static
IpV4OptionTraceRoute
ReadOptionTraceRout
e
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
public
IpV4OptionComplex
CreateInstanc
e
(
byte
[]
buffer
,
ref
int
offset
,
byte
valueLength
)
{
{
if
(
valueLength
!=
OptionValueLength
)
if
(
valueLength
!=
OptionValueLength
)
return
null
;
return
null
;
...
...
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