Is there any way to show the packet's dst ip address, src ip address and both port only?
var device = CaptureDeviceList.Instance.FirstOrDefault(dev => dev.Description.Contains("Ethernet"));//set capture interface to ethernet.
var defaultOutputType = StringOutputType.VerboseColored;//show the details of packet
var readTimeoutMilliseconds = 1000;
device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds);
device.Filter("not arp and host 192.168.0.10");//set filter to capture ip-packets only
PacketCapture d;
var status = device.GetNextPacket(out d);
var rawCapture = d.GetPacket();
var p = Packet.ParsePacket(rawCapture.LinkLayerType, rawCapture.Data);
Console.WriteLine(p.ToString(defaultOutputType));//It will show all the details but I just want to print source IP and destination IP and Port
Can it change to something like this?
var p = Packet.ParsePacket(rawCapture.LinkLayerType, rawCapture.Data);
Console.WriteLine("source = " + p.srcIP);
Console.WriteLine("destination = " + p.dstIP);
Console.WriteLine("source port = " + p.srcPort);
Console.WriteLine("destination port = " + p.dstPort);
Reference:
Go To->Examples->CapturingAndParsingPackets->Main.cs
You would first have to check whether the payload of the encapsulating packet (which might be an ethernet frame) is actually an ip-packet:
var p = Packet.ParsePacket(rawCapture.GetLinkLayers(), rawCapture.Data);
if (p.PayloadPacket is IPv4Packet ipPacket)
{
Console.WriteLine($"dst: {ipPacket.DestinationAddress} | src: {ipPacket.SourceAddress}");
}
Of course, you could also check for is IPPacket ... in case you want to track IPv6 packets as well.
Thanks to #johnmoarr, here's the code to print the port aswell:
var p = Packet.ParsePacket(rawCapture.GetLinkLayers(), rawCapture.Data);
if (p.PayloadPacket is IPv4Packet ipPacket)
{
Console.WriteLine($"dst: {ipPacket.DestinationAddress} | src: {ipPacket.SourceAddress}");
if (ipPacket.PayloadPacket is TcpPacket tcpPacket)
{
Console.WriteLine($"dst port: {tcpPacket.DestinationPort} | src port: {tcpPacket.SourcePort}");
}
else if (ipPacket.PayloadPacket is UdpPacket udpPacket)
{
code...
}
}
i created a proxy server in c# to replace my file on local
for example :
i get http header with HttpListener and parse it to take file url and then i build a fake Response to download the file from my local , but is it possible to do that with HTTPS too ?
i tried to do it but i get only CONNECT request type.
if is it possible , how can i do this ?
url is like this : https://sgst.prod.dl.playstation.net/sgst/prod/00/PPSA01876_00/app/info/62/f_c2855f23a9de280972d5dc1c1fae07240bb76193a65393a6e304588ffb111b8a/UP0001-PPSA01876_00-FARCRY6GAME00000.crc
and in fiddler :
This is Tunnel with CONNECT request type
and what i want to get is :
This is HTTPS GET request type with URL that i need
so this is my code but i get host only (Host: sgst.prod.dl.playstation.net)
private void QueryHandle(string query)
{
HeaderFields = ParseQuery(query);
if ((HeaderFields == null) || !HeaderFields.ContainsKey("Host"))
SendBadRequest();
else
{
int num;
string requestedPath;
int index;
if (HttpRequestType.ToUpper().Equals("CONNECT"))
{
index = RequestedPath.IndexOf(":");
if (index >= 0)
{
requestedPath = RequestedPath.Substring(0, index);
num = RequestedPath.Length > (index + 1) ? int.Parse(RequestedPath.Substring(index + 1)) : 443;
}
else
{
requestedPath = RequestedPath;
num = 80;
}
}
else
{
index = HeaderFields["Host"].IndexOf(":");
if (index > 0)
{
requestedPath = HeaderFields["Host"].Substring(0, index);
num = int.Parse(HeaderFields["Host"].Substring(index + 1));
}
else
{
requestedPath = HeaderFields["Host"];
num = 80;
}
if (HttpRequestType.ToUpper().Equals("POST"))
{
int tempnum = query.IndexOf("\r\n\r\n");
_mHttpPost = query.Substring(tempnum + 4);
}
}
var localFile = String.Empty;
if (MonitorLog.RegexUrl(RequestedUrl))
localFile = UrlOperate.MatchFile(RequestedUrl);
_uinfo.PsnUrl = string.IsNullOrEmpty(_uinfo.PsnUrl) ? RequestedUrl : _uinfo.PsnUrl;
if (!HttpRequestType.ToUpper().Equals("CONNECT") && localFile != string.Empty && File.Exists(localFile))
{
_uinfo.ReplacePath = localFile;
_updataUrlLog(_uinfo);
SendLocalFile(localFile, HeaderFields.ContainsKey("Range") ? HeaderFields["Range"] : null, HeaderFields.ContainsKey("Proxy-Connection") ? HeaderFields["Proxy-Connection"] : null);
}
if (HttpRequestType.ToUpper().Equals("CONNECT"))
{
IPHostEntry hostEntry;
hostEntry = Dns.GetHostEntry(requestedPath);
string server = hostEntry.AddressList[0].ToString();
IPAddress hostIp = IPAddress.Parse(server);
var remoteEp = new IPEndPoint(hostIp, num);
DestinationSocket = new Socket(remoteEp.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
DestinationSocket.BeginConnect(remoteEp, OnConnected, DestinationSocket);
_uinfo.Host = hostEntry.AddressList[0].ToString();
_uinfo.ReplacePath = string.Empty;
_updataUrlLog(_uinfo);
}
private void OnConnected(IAsyncResult ar)
{
try
{
if (DestinationSocket == null)
{
return;
}
string str;
DestinationSocket.EndConnect(ar);
if (HttpRequestType.ToUpper().Equals("CONNECT"))
{
if (ClientSocket != null)
{
str = HttpVersion + " 200 Connection Established\r\n\r\n";
ClientSocket.BeginSend(Encoding.ASCII.GetBytes(str), 0, str.Length, SocketFlags.Partial,
OnOkSent, ClientSocket);
}
}
else
{
str = RebuildQuery();
DestinationSocket.BeginSend(Encoding.ASCII.GetBytes(str), 0, str.Length, SocketFlags.None,
OnQuerySent, DestinationSocket);
}
}
catch
{
Dispose();
}
}
private void OnOkSent(IAsyncResult ar)
{
try
{
if (ClientSocket != null && ClientSocket.EndSend(ar) == -1)
{
Dispose();
}
else
{
StartRelay();
}
}
catch
{
Dispose();
}
}
so i am not familiar with socket , ssl , protocols ...
i will thank you for your help and sorry for my bad english
I am testing the example given in below link.
https://msdn.microsoft.com/en-us/library/system.net.security.sslstream.aspx
To generate certificates I am using the one with 40 userful answers SSLStream example - how do I get certificates that work?
To run the server I am using command
SslTcpServer.exe TempCert.cer
Below is the code from msdn where I am facing problem.
public static int Main(string[] args)
{
string serverCertificateName = null;
string machineName = null;
if (args == null ||args.Length <1 )
{
DisplayUsage();
}
// User can specify the machine name and server name.
// Server name must match the name on the server's certificate.
machineName = args[0];
if (args.Length <2 )
{
serverCertificateName = machineName;
}
else
{
serverCertificateName = args[1];
}
SslTcpClient.RunClient (machineName, serverCertificateName);
return 0;
}
I get below error when calling X509Certificate.CreateFromCertFile:
System.Security.Cryptography.CryptographicException: 'The system cannot find the file specified.
public static void RunServer(string certificate)
{
serverCertificate = X509Certificate.CreateFromCertFile(certificate);
// Create a TCP/IP (IPv4) socket and listen for incoming connections.
//serverCertificate = new X509Certificate2(certificate,"");
}
serverCertificateName is passed as argument and it should be just the name of the certificate or should i give the full path of the certificate?
If I give path of the certificate it is working fine.Then what is point in installing the certificates in the store? How can I get it from store and use it?
Here is some code that will return a list of the host names supported by installed certificates (that's a little more than you wanted, but should point you in the right direction):
System.Security.Cryptography.X509Certificates.X509Store store = new System.Security.Cryptography.X509Certificates.X509Store(System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine);
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly);
HashSet<string> certificateNames = new HashSet<string>();
foreach (System.Security.Cryptography.X509Certificates.X509Certificate2 mCert in store.Certificates)
{
// is this a UCC certificate?
System.Security.Cryptography.X509Certificates.X509Extension uccSan = mCert.Extensions["2.5.29.17"];
if (uccSan != null)
{
foreach (string nvp in uccSan.Format(true).Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
{
string[] parts = nvp.Split('=');
string name = parts[0];
string value = (parts.Length > 0) ? parts[1] : null;
if (String.Equals(name, "DNS Name", StringComparison.InvariantCultureIgnoreCase))
{
certificateNames.Add(value.ToLowerInvariant());
}
}
}
else // just a regular certificate--add the single name
{
string certificateHost = mCert.GetNameInfo(System.Security.Cryptography.X509Certificates.X509NameType.SimpleName, false);
certificateNames.Add(certificateHost.ToLowerInvariant());
}
}
return certificateNames;
Since IPEndpoint contains a ToString() method that outputs:
10.10.10.10:1010
There should also be Parse() and/or TryParse() method but there isn't.
I can split the string on the : and parse an IP address and a port.
But is there a more elegant way?
This is one solution...
public static IPEndPoint CreateIPEndPoint(string endPoint)
{
string[] ep = endPoint.Split(':');
if(ep.Length != 2) throw new FormatException("Invalid endpoint format");
IPAddress ip;
if(!IPAddress.TryParse(ep[0], out ip))
{
throw new FormatException("Invalid ip-adress");
}
int port;
if(!int.TryParse(ep[1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port))
{
throw new FormatException("Invalid port");
}
return new IPEndPoint(ip, port);
}
Edit: Added a version that will handle IPv4 and IPv6 the previous one only handles IPv4.
// Handles IPv4 and IPv6 notation.
public static IPEndPoint CreateIPEndPoint(string endPoint)
{
string[] ep = endPoint.Split(':');
if (ep.Length < 2) throw new FormatException("Invalid endpoint format");
IPAddress ip;
if (ep.Length > 2)
{
if (!IPAddress.TryParse(string.Join(":", ep, 0, ep.Length - 1), out ip))
{
throw new FormatException("Invalid ip-adress");
}
}
else
{
if (!IPAddress.TryParse(ep[0], out ip))
{
throw new FormatException("Invalid ip-adress");
}
}
int port;
if (!int.TryParse(ep[ep.Length - 1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port))
{
throw new FormatException("Invalid port");
}
return new IPEndPoint(ip, port);
}
I had the requirement of parsing an IPEndpoint with IPv6, v4 and hostnames. The solution I wrote is listed below:
public static IPEndPoint Parse(string endpointstring)
{
return Parse(endpointstring, -1);
}
public static IPEndPoint Parse(string endpointstring, int defaultport)
{
if (string.IsNullOrEmpty(endpointstring)
|| endpointstring.Trim().Length == 0)
{
throw new ArgumentException("Endpoint descriptor may not be empty.");
}
if (defaultport != -1 &&
(defaultport < IPEndPoint.MinPort
|| defaultport > IPEndPoint.MaxPort))
{
throw new ArgumentException(string.Format("Invalid default port '{0}'", defaultport));
}
string[] values = endpointstring.Split(new char[] { ':' });
IPAddress ipaddy;
int port = -1;
//check if we have an IPv6 or ports
if (values.Length <= 2) // ipv4 or hostname
{
if (values.Length == 1)
//no port is specified, default
port = defaultport;
else
port = getPort(values[1]);
//try to use the address as IPv4, otherwise get hostname
if (!IPAddress.TryParse(values[0], out ipaddy))
ipaddy = getIPfromHost(values[0]);
}
else if (values.Length > 2) //ipv6
{
//could [a:b:c]:d
if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]"))
{
string ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray());
ipaddy = IPAddress.Parse(ipaddressstring);
port = getPort(values[values.Length - 1]);
}
else //[a:b:c] or a:b:c
{
ipaddy = IPAddress.Parse(endpointstring);
port = defaultport;
}
}
else
{
throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", endpointstring));
}
if (port == -1)
throw new ArgumentException(string.Format("No port specified: '{0}'", endpointstring));
return new IPEndPoint(ipaddy, port);
}
private static int getPort(string p)
{
int port;
if (!int.TryParse(p, out port)
|| port < IPEndPoint.MinPort
|| port > IPEndPoint.MaxPort)
{
throw new FormatException(string.Format("Invalid end point port '{0}'", p));
}
return port;
}
private static IPAddress getIPfromHost(string p)
{
var hosts = Dns.GetHostAddresses(p);
if (hosts == null || hosts.Length == 0)
throw new ArgumentException(string.Format("Host not found: {0}", p));
return hosts[0];
}
This has been tested to work with the following examples:
0.0.0.0:100
0.0.0.0
[::1]:100
[::1]
::1
[a:b:c:d]
[a:b:c:d]:100
example.org
example.org:100
It looks like there is already a built in Parse method that handles ip4 and ip6 addresses
http://msdn.microsoft.com/en-us/library/system.net.ipaddress.parse%28v=vs.110%29.aspx
// serverIP can be in ip4 or ip6 format
string serverIP = "192.168.0.1";
int port = 8000;
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(serverIP), port);
Here is my version of parsing text to IPEndPoint:
private static IPEndPoint ParseIPEndPoint(string text)
{
Uri uri;
if (Uri.TryCreate(text, UriKind.Absolute, out uri))
return new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port < 0 ? 0 : uri.Port);
if (Uri.TryCreate(String.Concat("tcp://", text), UriKind.Absolute, out uri))
return new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port < 0 ? 0 : uri.Port);
if (Uri.TryCreate(String.Concat("tcp://", String.Concat("[", text, "]")), UriKind.Absolute, out uri))
return new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port < 0 ? 0 : uri.Port);
throw new FormatException("Failed to parse text to IPEndPoint");
}
Tested with:
0.0.0.0
0.0.0.0:100
[::1]:100
[::1]:0
::1
[2001:db8:85a3:8d3:1319:8a2e:370:7348]
[2001:db8:85a3:8d3:1319:8a2e:370:7348]:100
http://0.0.0.0
http://0.0.0.0:100
http://[::1]
http://[::1]:100
https://0.0.0.0
https://[::1]
Apparently, IPEndPoint.Parse and IPEndPoint.TryParse were added in .NET Core 3.0.
In case you're targeting it, give those methods a try! The implementation is seen in the link above.
Here is a very simple solution, it handles both IPv4 and IPv6.
public class IPEndPoint : System.Net.IPEndPoint
{
public IPEndPoint(long address, int port) : base(address, port) { }
public IPEndPoint(IPAddress address, int port) : base(address, port) { }
public static bool TryParse(string value, out IPEndPoint result)
{
if (!Uri.TryCreate($"tcp://{value}", UriKind.Absolute, out Uri uri) ||
!IPAddress.TryParse(uri.Host, out IPAddress ipAddress) ||
uri.Port < 0 || uri.Port > 65535)
{
result = default(IPEndPoint);
return false;
}
result = new IPEndPoint(ipAddress, uri.Port);
return true;
}
}
Simply use the TryParse the way you would normally.
IPEndPoint.TryParse("192.168.1.10:80", out IPEndPoint ipv4Result);
IPEndPoint.TryParse("[fd00::]:8080", out IPEndPoint ipv6Result);
This will do IPv4 and IPv6. An extension method for this functionality would be on System.string. Not sure I want this option for every string I have in the project.
private static IPEndPoint IPEndPointParse(string endpointstring)
{
string[] values = endpointstring.Split(new char[] {':'});
if (2 > values.Length)
{
throw new FormatException("Invalid endpoint format");
}
IPAddress ipaddress;
string ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray());
if (!IPAddress.TryParse(ipaddressstring, out ipaddress))
{
throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", ipaddressstring));
}
int port;
if (!int.TryParse(values[values.Length - 1], out port)
|| port < IPEndPoint.MinPort
|| port > IPEndPoint.MaxPort)
{
throw new FormatException(string.Format("Invalid end point port '{0}'", values[values.Length - 1]));
}
return new IPEndPoint(ipaddress, port);
}
Create an extension method Parse and TryParse. I guess that is more elegant.
The parsing code is simple for an IPv4 endpoint, but IPEndPoint.ToString() on an IPv6 address also uses the same colon notation, but conflicts with the IPv6 address's colon notation. I was hoping Microsoft would spend the effort writing this ugly parsing code instead, but I guess I'll have to...
This is my take on the parsing of an IPEndPoint. Using the Uri class avoids having to handle the specifics of IPv4/6, and the presence or not of the port. You could can modify the default port for your application.
public static bool TryParseEndPoint(string ipPort, out System.Net.IPEndPoint result)
{
result = null;
string scheme = "iiiiiiiiiaigaig";
GenericUriParserOptions options =
GenericUriParserOptions.AllowEmptyAuthority |
GenericUriParserOptions.NoQuery |
GenericUriParserOptions.NoUserInfo |
GenericUriParserOptions.NoFragment |
GenericUriParserOptions.DontCompressPath |
GenericUriParserOptions.DontConvertPathBackslashes |
GenericUriParserOptions.DontUnescapePathDotsAndSlashes;
UriParser.Register(new GenericUriParser(options), scheme, 1337);
Uri parsedUri;
if (!Uri.TryCreate(scheme + "://" + ipPort, UriKind.Absolute, out parsedUri))
return false;
System.Net.IPAddress parsedIP;
if (!System.Net.IPAddress.TryParse(parsedUri.Host, out parsedIP))
return false;
result = new System.Net.IPEndPoint(parsedIP, parsedUri.Port);
return true;
}
If the port number is always provided after a ':', the following method may be a more elegant option (in code length instead of efficiency).
public static IPEndpoint ParseIPEndpoint(string ipEndPoint) {
int ipAddressLength = ipEndPoint.LastIndexOf(':');
return new IPEndPoint(
IPAddress.Parse(ipEndPoint.Substring(0, ipAddressLength)),
Convert.ToInt32(ipEndPoint.Substring(ipAddressLength + 1)));
}
It works fine for my simple application without considering complex IP address format.
A rough conversion of the .NET 3 code (for .NET 4.7) would be this:
// ReSharper disable once InconsistentNaming
public static class IPEndPointExtensions
{
public static bool TryParse(string s, out IPEndPoint result)
{
int addressLength = s.Length; // If there's no port then send the entire string to the address parser
int lastColonPos = s.LastIndexOf(':');
// Look to see if this is an IPv6 address with a port.
if (lastColonPos > 0)
{
if (s[lastColonPos - 1] == ']')
{
addressLength = lastColonPos;
}
// Look to see if this is IPv4 with a port (IPv6 will have another colon)
else if (s.Substring(0, lastColonPos).LastIndexOf(':') == -1)
{
addressLength = lastColonPos;
}
}
if (IPAddress.TryParse(s.Substring(0, addressLength), out IPAddress address))
{
uint port = 0;
if (addressLength == s.Length ||
(uint.TryParse(s.Substring(addressLength + 1), NumberStyles.None, CultureInfo.InvariantCulture, out port) && port <= IPEndPoint.MaxPort))
{
result = new IPEndPoint(address, (int)port);
return true;
}
}
result = null;
return false;
}
public static IPEndPoint Parse(string s)
{
if (s == null)
{
throw new ArgumentNullException(nameof(s));
}
if (TryParse(s, out IPEndPoint result))
{
return result;
}
throw new FormatException(#"An invalid IPEndPoint was specified.");
}
}
using System;
using System.Net;
static class Helper {
public static IPEndPoint ToIPEndPoint(this string value, int port = IPEndPoint.MinPort) {
if (string.IsNullOrEmpty(value) || ! IPAddress.TryParse(value, out var address))
return null;
var offset = (value = value.Replace(address.ToString(), string.Empty)).LastIndexOf(':');
if (offset >= 0)
if (! int.TryParse(value.Substring(offset + 1), out port) || port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
return null;
return new IPEndPoint(address, port);
}
}
class Program {
static void Main() {
foreach (var sample in new [] {
// See https://docops.ca.com/ca-data-protection-15/en/implementing/platform-deployment/technical-information/ipv6-address-and-port-formats
"192.168.0.3",
"fe80::214:c2ff:fec8:c920",
"10.0.1.53-10.0.1.80",
"10.0",
"10/7",
"2001:0db8:85a3/48",
"192.168.0.5:10",
"[fe80::e828:209d:20e:c0ae]:375",
":137-139",
"192.168:1024-65535",
"[fe80::]-[fe81::]:80"
}) {
var point = sample.ToIPEndPoint();
var report = point == null ? "NULL" : $#"IPEndPoint {{
Address: {point.Address}
AddressFamily: {point.AddressFamily}
Port: {point.Port}
}}";
Console.WriteLine($#"""{sample}"" to IPEndPoint is {report}
");
}
}
}
IPAddress ipAddress = IPAddress.Parse(yourIPAddress);
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, Convert.ToInt16(yourPortAddress));