Skip to content

Commit 212c1cc

Browse files
committed
Added some basic socket code.
1 parent e844179 commit 212c1cc

File tree

4 files changed

+447
-0
lines changed

4 files changed

+447
-0
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright 2020 Google Inc. All Rights Reserved.
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+
using System;
16+
using System.Net;
17+
using System.Net.Sockets;
18+
19+
namespace NtApiDotNet.Net.Sockets
20+
{
21+
/// <summary>
22+
/// Endpoint implementation for a HyperV socket.
23+
/// </summary>
24+
[Serializable]
25+
public class HyperVEndPoint : EndPoint
26+
{
27+
/// <summary>
28+
/// Address family.
29+
/// </summary>
30+
public readonly static AddressFamily AF_HYPERV = (AddressFamily)34;
31+
/// <summary>
32+
/// Protocol type for HyperV sockets.
33+
/// </summary>
34+
public readonly static ProtocolType HV_PROTOCOL_RAW = (ProtocolType)1;
35+
36+
private static void CopyGuid(Guid guid, SocketAddress address, int offset)
37+
{
38+
byte[] bytes = guid.ToByteArray();
39+
for (int i = 0; i < bytes.Length; ++i)
40+
{
41+
address[i + offset] = bytes[i];
42+
}
43+
}
44+
45+
private static Guid ReadGuid(SocketAddress address, int offset)
46+
{
47+
byte[] bytes = new byte[16];
48+
for (int i = 0; i < bytes.Length; ++i)
49+
{
50+
bytes[i] = address[i + offset];
51+
}
52+
return new Guid(bytes);
53+
}
54+
55+
/// <summary>
56+
/// Default constructor.
57+
/// </summary>
58+
public HyperVEndPoint()
59+
{
60+
}
61+
62+
/// <summary>
63+
/// Constructor.
64+
/// </summary>
65+
public HyperVEndPoint(Guid service_id, Guid vm_id)
66+
{
67+
ServiceId = service_id;
68+
VmId = vm_id;
69+
}
70+
71+
/// <summary>
72+
/// Get or set the service ID.
73+
/// </summary>
74+
public Guid ServiceId { get; set; }
75+
76+
/// <summary>
77+
/// Get or set the VM ID.
78+
/// </summary>
79+
public Guid VmId { get; set; }
80+
81+
/// <summary>
82+
/// Address family.
83+
/// </summary>
84+
public override AddressFamily AddressFamily => AF_HYPERV;
85+
86+
/// <summary>
87+
/// Serialize the socket address.
88+
/// </summary>
89+
/// <returns>The serialized address.</returns>
90+
public override SocketAddress Serialize()
91+
{
92+
// At least on Windows you need to allocate the entire address otherwise bad things happen.
93+
var addr = new SocketAddress(AddressFamily, 36);
94+
CopyGuid(VmId, addr, 4);
95+
CopyGuid(ServiceId, addr, 20);
96+
return addr;
97+
}
98+
99+
/// <summary>
100+
/// Create a endpoint from a socket address.
101+
/// </summary>
102+
/// <param name="address">The socket address.</param>
103+
/// <returns>The created endpoint.</returns>
104+
public override EndPoint Create(SocketAddress address)
105+
{
106+
if (address.Family != AF_HYPERV)
107+
throw new ArgumentException("Family in socket address isn't AF_HYPERV");
108+
return new HyperVEndPoint(ReadGuid(address, 20), ReadGuid(address, 4));
109+
}
110+
111+
/// <summary>
112+
/// Overridden ToString method.
113+
/// </summary>
114+
/// <returns>The endpoint as a string.</returns>
115+
public override string ToString()
116+
{
117+
return $"{ServiceId} - {VmId}";
118+
}
119+
120+
/// <summary>
121+
/// Overridden equals method.
122+
/// </summary>
123+
/// <param name="obj">The object to compare.</param>
124+
/// <returns>True if the objects are equal.</returns>
125+
public override bool Equals(object obj)
126+
{
127+
if (!(obj is HyperVEndPoint))
128+
{
129+
return false;
130+
}
131+
132+
HyperVEndPoint ep = (HyperVEndPoint)obj;
133+
return ep.ServiceId == ServiceId && ep.VmId == VmId;
134+
}
135+
136+
/// <summary>
137+
/// Get endpoint hash code.
138+
/// </summary>
139+
/// <returns>The hashcode.</returns>
140+
public override int GetHashCode()
141+
{
142+
return ServiceId.GetHashCode() ^ VmId.GetHashCode();
143+
}
144+
}
145+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright 2020 Google Inc. All Rights Reserved.
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+
using System;
16+
using System.Collections.Generic;
17+
18+
namespace NtApiDotNet.Net.Sockets
19+
{
20+
/// <summary>
21+
/// GUIDs for HyperV Sockets.
22+
/// </summary>
23+
public static class HyperVSocketGuids
24+
{
25+
private static Dictionary<Guid, string> _guid_to_name;
26+
27+
private static Dictionary<Guid, string> GetGuidToName()
28+
{
29+
if (_guid_to_name == null)
30+
{
31+
_guid_to_name = new Dictionary<Guid, string>();
32+
foreach (var field in typeof(HyperVSocketGuids).GetFields())
33+
{
34+
if (field.FieldType == typeof(Guid))
35+
{
36+
Guid g = (Guid)field.GetValue(null);
37+
_guid_to_name.Add(g, field.Name);
38+
}
39+
}
40+
}
41+
return _guid_to_name;
42+
}
43+
44+
/// <summary>
45+
/// Allows accepting connections from all partitions.
46+
/// </summary>
47+
public readonly static Guid HV_GUID_WILDCARD = Guid.Empty;
48+
/// <summary>
49+
/// Broadcast. Send to all sockets.
50+
/// </summary>
51+
public readonly static Guid HV_GUID_BROADCAST = new Guid(0xFFFFFFFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
52+
/// <summary>
53+
/// Allows accepting connections form all child partitions.
54+
/// </summary>
55+
public readonly static Guid HV_GUID_CHILDREN = new Guid(0x90db8b89, 0x0d35, 0x4f79, 0x8c, 0xe9, 0x49, 0xea, 0x0a, 0xc8, 0xb7, 0xcd);
56+
/// <summary>
57+
/// Connect or bind to the loopback address.
58+
/// </summary>
59+
public readonly static Guid HV_GUID_LOOPBACK = new Guid(0xe0e16197, 0xdd56, 0x4a10, 0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38);
60+
/// <summary>
61+
/// Connect to the parent container.
62+
/// </summary>
63+
public readonly static Guid HV_GUID_PARENT = new Guid(0xa42e7cda, 0xd03f, 0x480c, 0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78);
64+
/// <summary>
65+
/// Connect to the silo host container.
66+
/// </summary>
67+
public readonly static Guid HV_GUID_SILOHOST = new Guid(0x36bd0c5c, 0x7276, 0x4223, 0x88, 0xba, 0x7d, 0x03, 0xb6, 0x54, 0xc5, 0x68);
68+
/// <summary>
69+
/// VSOCK template GUID.
70+
/// </summary>
71+
public readonly static Guid HV_GUID_VSOCK_TEMPLATE = new Guid(0x00000000, 0xfacb, 0x11e6, 0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3);
72+
73+
/// <summary>
74+
/// Create an address for a VSOCK port.
75+
/// </summary>
76+
/// <param name="vsock">The VSOCK port.</param>
77+
/// <returns>The address.</returns>
78+
public static Guid CreateVSockAddress(int vsock)
79+
{
80+
byte[] ba = HV_GUID_VSOCK_TEMPLATE.ToByteArray();
81+
Buffer.BlockCopy(new int[] { vsock }, 0, ba, 0, 4);
82+
return new Guid(ba);
83+
}
84+
85+
/// <summary>
86+
/// Checks if an address is a VSOCK address.
87+
/// </summary>
88+
/// <param name="address">The address to check.</param>
89+
/// <returns>True if a VSOCK address.</returns>
90+
public static bool IsVSockAddress(Guid address)
91+
{
92+
byte[] ba = address.ToByteArray();
93+
ba[0] = 0;
94+
ba[1] = 0;
95+
ba[2] = 0;
96+
ba[3] = 0;
97+
return new Guid(ba) == HV_GUID_VSOCK_TEMPLATE;
98+
}
99+
100+
/// <summary>
101+
/// Get the port for a VSOCK address.
102+
/// </summary>
103+
/// <param name="address">The address to query.</param>
104+
/// <returns>The VSOCK port.</returns>
105+
/// <exception cref="ArgumentException">Throw if not a valid VSOCK address.</exception>
106+
public static int GetVSockPort(Guid address)
107+
{
108+
if (!IsVSockAddress(address))
109+
throw new ArgumentException("Invalid VSock address.", nameof(address));
110+
return BitConverter.ToInt32(address.ToByteArray(), 0);
111+
}
112+
113+
/// <summary>
114+
/// Convert an address to a string.
115+
/// </summary>
116+
/// <param name="address">The address to convert.</param>
117+
/// <returns>The converted address. If not symbolic name found will return the GUID as a string.</returns>
118+
public static string AddressToString(Guid address)
119+
{
120+
if (IsVSockAddress(address))
121+
return $"HV_GUID_VSOCK[{GetVSockPort(address)}]";
122+
var dict = GetGuidToName();
123+
if (dict.ContainsKey(address))
124+
return dict[address];
125+
return address.ToString();
126+
}
127+
}
128+
}

0 commit comments

Comments
 (0)