mirror of
https://github.com/netchx/netch.git
synced 2026-03-26 18:49:46 +08:00
done
This commit is contained in:
38
Netch/3rd/DnsClient.NET/Interop/DisposableIntPtr.cs
Normal file
38
Netch/3rd/DnsClient.NET/Interop/DisposableIntPtr.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
internal class DisposableIntPtr : IDisposable
|
||||
{
|
||||
public IntPtr Ptr => _ptr;
|
||||
|
||||
public bool IsValid { get; private set; } = true;
|
||||
|
||||
private IntPtr _ptr;
|
||||
|
||||
private DisposableIntPtr()
|
||||
{
|
||||
}
|
||||
|
||||
public static DisposableIntPtr Alloc(int size)
|
||||
{
|
||||
var ptr = new DisposableIntPtr();
|
||||
try
|
||||
{
|
||||
ptr._ptr = Marshal.AllocHGlobal(size);
|
||||
}
|
||||
catch (OutOfMemoryException)
|
||||
{
|
||||
ptr.IsValid = false;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Marshal.FreeHGlobal(_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Netch/3rd/DnsClient.NET/Interop/Interop.Libraries.cs
Normal file
7
Netch/3rd/DnsClient.NET/Interop/Interop.Libraries.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
internal static partial class Interop
|
||||
{
|
||||
internal static class Libraries
|
||||
{
|
||||
internal const string IpHlpApi = "iphlpapi.dll";
|
||||
}
|
||||
}
|
||||
189
Netch/3rd/DnsClient.NET/Interop/Linux/RowConfigReader.cs
Normal file
189
Netch/3rd/DnsClient.NET/Interop/Linux/RowConfigReader.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper for reading config files where each row is a key-value data pair.
|
||||
/// The input key-values must not have any whitespace within them.
|
||||
/// Keys are only matched if they begin a line, with no preceding whitespace.
|
||||
/// </summary>
|
||||
internal struct RowConfigReader
|
||||
{
|
||||
private readonly string _buffer;
|
||||
private readonly StringComparison _comparisonKind;
|
||||
private int _currentIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new RowConfigReader which reads from the given string.
|
||||
/// <param name="buffer">The string to parse through.</param>
|
||||
/// </summary>
|
||||
public RowConfigReader(string buffer)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_comparisonKind = StringComparison.Ordinal;
|
||||
_currentIndex = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new RowConfigReader which reads from the given string.
|
||||
/// <param name="buffer">The string to parse through.</param>
|
||||
/// <param name="comparisonKind">The comparison kind to use.</param>
|
||||
/// </summary>
|
||||
public RowConfigReader(string buffer, StringComparison comparisonKind)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_comparisonKind = comparisonKind;
|
||||
_currentIndex = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next occurrence of the given key, from the current position of the reader,
|
||||
/// or throws if no occurrence of the key exists in the remainder of the string.
|
||||
/// </summary>
|
||||
public string GetNextValue(string key)
|
||||
{
|
||||
string value;
|
||||
if (!TryGetNextValue(key, out value))
|
||||
{
|
||||
throw new InvalidOperationException("Couldn't get next value with key " + key);
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the next occurrence of the given key from the current position of the reader.
|
||||
/// If successful, returns true and stores the result in 'value'. Otherwise, returns false.
|
||||
/// </summary>
|
||||
public bool TryGetNextValue(string key, out string value)
|
||||
{
|
||||
Debug.Assert(_buffer != null);
|
||||
if (_currentIndex >= _buffer.Length)
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// First, find the key, by repeatedly searching for occurrences.
|
||||
// We only match an occurrence if it starts a line, by itself, with no preceding whitespace.
|
||||
int keyIndex;
|
||||
if (!TryFindNextKeyOccurrence(key, _currentIndex, out keyIndex))
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Next, we will take the end of the line, and look backwards for the start of the value.
|
||||
// NOTE: This assumes that the "value" does not have any whitespace in it, nor is there any
|
||||
// after. This is the format of most "row-based" config files in /proc/net, etc.
|
||||
int afterKey = keyIndex + key.Length;
|
||||
|
||||
int endOfValue;
|
||||
int endOfLine = _buffer.IndexOf(Environment.NewLine, afterKey, _comparisonKind);
|
||||
if (endOfLine == -1)
|
||||
{
|
||||
// There may not be a newline after this key, if we've reached the end of the file.
|
||||
endOfLine = _buffer.Length - 1;
|
||||
endOfValue = endOfLine;
|
||||
}
|
||||
else
|
||||
{
|
||||
endOfValue = endOfLine - 1;
|
||||
}
|
||||
|
||||
int lineLength = endOfLine - keyIndex; // keyIndex is the start of the line.
|
||||
int whitespaceBeforeValue = _buffer.LastIndexOf('\t', endOfLine, lineLength);
|
||||
if (whitespaceBeforeValue == -1)
|
||||
{
|
||||
whitespaceBeforeValue = _buffer.LastIndexOf(' ', endOfLine, lineLength); // try space as well
|
||||
}
|
||||
|
||||
int valueIndex = whitespaceBeforeValue + 1; // Get the first character after the whitespace.
|
||||
int valueLength = endOfValue - whitespaceBeforeValue;
|
||||
if (valueIndex <= keyIndex || valueIndex == -1 || valueLength == 0)
|
||||
{
|
||||
// No value found after the key.
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = _buffer.Substring(valueIndex, valueLength); // Grab the whole value string.
|
||||
|
||||
_currentIndex = endOfLine + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryFindNextKeyOccurrence(string key, int startIndex, out int keyIndex)
|
||||
{
|
||||
// Loop until end of file is reached, or a match is found.
|
||||
while (true)
|
||||
{
|
||||
keyIndex = _buffer.IndexOf(key, startIndex, _comparisonKind);
|
||||
if (keyIndex == -1)
|
||||
{
|
||||
// Reached end of string with no match.
|
||||
return false;
|
||||
}
|
||||
// Check If the match is at the beginning of the string, or is preceded by a newline.
|
||||
else if (keyIndex == 0
|
||||
|| (keyIndex >= Environment.NewLine.Length && _buffer.Substring(keyIndex - Environment.NewLine.Length, Environment.NewLine.Length) == Environment.NewLine))
|
||||
{
|
||||
// Check if the match is followed by whitespace, meaning it is not part of a larger word.
|
||||
if (HasFollowingWhitespace(keyIndex, key.Length))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
startIndex = startIndex + key.Length;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasFollowingWhitespace(int keyIndex, int length)
|
||||
{
|
||||
return (keyIndex + length < _buffer.Length)
|
||||
&& (_buffer[keyIndex + length] == ' ' || _buffer[keyIndex + length] == '\t');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next occurrence of the key in the string, and parses it as an Int32.
|
||||
/// Throws if the key is not found in the remainder of the string, or if the key
|
||||
/// cannot be successfully parsed into an Int32.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is mainly provided as a helper because most Linux config/info files
|
||||
/// store integral data.
|
||||
/// </remarks>
|
||||
public int GetNextValueAsInt32(string key)
|
||||
{
|
||||
// PERF: We don't need to allocate a new string here, we can parse an Int32 "in-place" in the existing string.
|
||||
string value = GetNextValue(key);
|
||||
int result;
|
||||
if (int.TryParse(value, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Unable to parse value " + value + " of key " + key + " as an Int32.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the value of the first occurrence of the given key contained in the string given.
|
||||
/// </summary>
|
||||
/// <param name="data">The key-value row configuration string.</param>
|
||||
/// <param name="key">The key to find.</param>
|
||||
/// <returns>The value of the row containing the first occurrence of the key.</returns>
|
||||
public static string ReadFirstValueFromString(string data, string key)
|
||||
{
|
||||
return new RowConfigReader(data).GetNextValue(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
// TODO: Remove if fixed
|
||||
// This code is from https://github.com/dotnet/corefx
|
||||
// Will be removed whenever the bugs reading network information on linux are fixed and
|
||||
// I can use the Managed version.
|
||||
|
||||
namespace DnsClient.Linux
|
||||
{
|
||||
internal static partial class StringParsingHelpers
|
||||
{
|
||||
internal static string ParseDnsSuffixFromResolvConfFile(string filePath)
|
||||
{
|
||||
string data = File.ReadAllText(filePath);
|
||||
RowConfigReader rcr = new RowConfigReader(data);
|
||||
string dnsSuffix;
|
||||
|
||||
return rcr.TryGetNextValue("search", out dnsSuffix) ? dnsSuffix : string.Empty;
|
||||
}
|
||||
|
||||
internal static List<IPAddress> ParseDnsAddressesFromResolvConfFile(string filePath)
|
||||
{
|
||||
// Parse /etc/resolv.conf for all of the "nameserver" entries.
|
||||
// These are the DNS servers the machine is configured to use.
|
||||
// On OSX, this file is not directly used by most processes for DNS
|
||||
// queries/routing, but it is automatically generated instead, with
|
||||
// the machine's DNS servers listed in it.
|
||||
string data = File.ReadAllText(filePath);
|
||||
RowConfigReader rcr = new RowConfigReader(data);
|
||||
List<IPAddress> addresses = new List<IPAddress>();
|
||||
|
||||
string addressString = null;
|
||||
while (rcr.TryGetNextValue("nameserver", out addressString))
|
||||
{
|
||||
IPAddress parsedAddress;
|
||||
if (IPAddress.TryParse(addressString, out parsedAddress))
|
||||
{
|
||||
addresses.Add(parsedAddress);
|
||||
}
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#if !NET45
|
||||
|
||||
namespace DnsClient.Windows.IpHlpApi
|
||||
{
|
||||
internal class FixedNetworkInformation
|
||||
{
|
||||
private FixedNetworkInformation()
|
||||
{
|
||||
}
|
||||
|
||||
public ICollection<IPAddress> DnsAddresses { get; private set; }
|
||||
|
||||
public string DomainName { get; private set; }
|
||||
|
||||
public string HostName { get; private set; }
|
||||
|
||||
public static FixedNetworkInformation GetFixedInformation()
|
||||
{
|
||||
var info = new FixedNetworkInformation();
|
||||
uint size = 0;
|
||||
DisposableIntPtr buffer = null;
|
||||
Interop.IpHlpApi.FIXED_INFO fixedInfo = new Interop.IpHlpApi.FIXED_INFO();
|
||||
|
||||
uint result = Interop.IpHlpApi.GetNetworkParams(IntPtr.Zero, ref size);
|
||||
|
||||
while (result == Interop.IpHlpApi.ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
using (buffer = DisposableIntPtr.Alloc((int)size))
|
||||
{
|
||||
if (buffer.IsValid)
|
||||
{
|
||||
result = Interop.IpHlpApi.GetNetworkParams(buffer.Ptr, ref size);
|
||||
if (result == Interop.IpHlpApi.ERROR_SUCCESS)
|
||||
{
|
||||
fixedInfo = Marshal.PtrToStructure<Interop.IpHlpApi.FIXED_INFO>(buffer.Ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Win32Exception((int)result);
|
||||
}
|
||||
|
||||
var dnsAddresses = new List<IPAddress>();
|
||||
Interop.IpHlpApi.IP_ADDR_STRING addr = fixedInfo.DnsServerList;
|
||||
IPAddress ip;
|
||||
|
||||
if (IPAddress.TryParse(addr.IpAddress, out ip))
|
||||
{
|
||||
dnsAddresses.Add(ip);
|
||||
|
||||
while (addr.Next != IntPtr.Zero)
|
||||
{
|
||||
addr = Marshal.PtrToStructure<Interop.IpHlpApi.IP_ADDR_STRING>(addr.Next);
|
||||
if (IPAddress.TryParse(addr.IpAddress, out ip))
|
||||
{
|
||||
dnsAddresses.Add(ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info.HostName = fixedInfo.hostName;
|
||||
info.DomainName = fixedInfo.domainName;
|
||||
info.DnsAddresses = dnsAddresses.ToArray();
|
||||
|
||||
return info;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new OutOfMemoryException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
internal static partial class IpHlpApi
|
||||
{
|
||||
internal const uint ERROR_SUCCESS = 0;
|
||||
internal const uint ERROR_INVALID_FUNCTION = 1;
|
||||
internal const uint ERROR_NO_SUCH_DEVICE = 2;
|
||||
internal const uint ERROR_INVALID_DATA = 13;
|
||||
internal const uint ERROR_INVALID_PARAMETER = 87;
|
||||
internal const uint ERROR_BUFFER_OVERFLOW = 111;
|
||||
internal const uint ERROR_INSUFFICIENT_BUFFER = 122;
|
||||
internal const uint ERROR_NO_DATA = 232;
|
||||
internal const uint ERROR_IO_PENDING = 997;
|
||||
internal const uint ERROR_NOT_FOUND = 1168;
|
||||
|
||||
[DllImport(Libraries.IpHlpApi)]
|
||||
internal extern static uint GetAdaptersAddresses(
|
||||
AddressFamily family,
|
||||
uint flags,
|
||||
IntPtr pReserved,
|
||||
IntPtr adapterAddresses,
|
||||
ref uint outBufLen);
|
||||
|
||||
[DllImport(Libraries.IpHlpApi, ExactSpelling = true)]
|
||||
internal extern static uint GetNetworkParams(IntPtr pFixedInfo, ref uint pOutBufLen);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal struct FIXED_INFO
|
||||
{
|
||||
public const int MAX_HOSTNAME_LEN = 128;
|
||||
public const int MAX_DOMAIN_NAME_LEN = 128;
|
||||
public const int MAX_SCOPE_ID_LEN = 256;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_HOSTNAME_LEN + 4)]
|
||||
public string hostName;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_DOMAIN_NAME_LEN + 4)]
|
||||
public string domainName;
|
||||
|
||||
public IntPtr currentDnsServer; // IpAddressList*
|
||||
public IP_ADDR_STRING DnsServerList;
|
||||
public uint nodeType;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_SCOPE_ID_LEN + 4)]
|
||||
public string scopeId;
|
||||
|
||||
public bool enableRouting;
|
||||
public bool enableProxy;
|
||||
public bool enableDns;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal struct IP_ADDR_STRING
|
||||
{
|
||||
public IntPtr Next; // struct _IpAddressList*
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
|
||||
public string IpAddress;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
|
||||
public string IpMask;
|
||||
|
||||
public uint Context;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user