// This code is derived from jcifs smb client library // Ported by J. Arturo // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; using System.IO; using System.Linq; using System.Net; using SharpCifs.Netbios; using SharpCifs.Util; using SharpCifs.Util.Sharpen; using Extensions = SharpCifs.Util.Sharpen.Extensions; using System.Threading.Tasks; namespace SharpCifs { /// ///

Under normal conditions it is not necessary to use /// this class to use jCIFS properly. ///

/// ///

Under normal conditions it is not necessary to use /// this class to use jCIFS properly. Name resolusion is /// handled internally to the jcifs.smb package. ///

/// This class is a wrapper for both /// Jcifs.Netbios.NbtAddress /// and /// System.Net.IPAddress /// . The name resolution mechanisms /// used will systematically query all available configured resolution /// services including WINS, broadcasts, DNS, and LMHOSTS. See /// Setting Name Resolution Properties /// and the jcifs.resolveOrder property. Changing /// jCIFS name resolution properties can greatly affect the behavior of /// the client and may be necessary for proper operation. ///

/// This class should be used in favor of InetAddress to resolve /// hostnames on LANs and WANs that support a mixture of NetBIOS/WINS and /// DNS resolvable hosts. /// public class UniAddress { private const int ResolverWins = 0; private const int ResolverBcast = 1; private const int ResolverDns = 2; private const int ResolverLmhosts = 3; private static int[] _resolveOrder; private static IPAddress _baddr; private static LogStream _log = LogStream.GetInstance(); static UniAddress() { string ro = Config.GetProperty("jcifs.resolveOrder"); IPAddress nbns = NbtAddress.GetWinsAddress(); try { _baddr = Config.GetInetAddress("jcifs.netbios.baddr", Extensions.GetAddressByName("255.255.255.255")); } catch (UnknownHostException) { } if (string.IsNullOrEmpty(ro)) { if (nbns == null) { _resolveOrder = new int[3]; _resolveOrder[0] = ResolverLmhosts; _resolveOrder[1] = ResolverDns; _resolveOrder[2] = ResolverBcast; } else { _resolveOrder = new int[4]; _resolveOrder[0] = ResolverLmhosts; _resolveOrder[1] = ResolverWins; _resolveOrder[2] = ResolverDns; _resolveOrder[3] = ResolverBcast; } } else { int[] tmp = new int[4]; StringTokenizer st = new StringTokenizer(ro, ","); int i = 0; while (st.HasMoreTokens()) { string s = st.NextToken().Trim(); if (Runtime.EqualsIgnoreCase(s, "LMHOSTS")) { tmp[i++] = ResolverLmhosts; } else { if (Runtime.EqualsIgnoreCase(s, "WINS")) { if (nbns == null) { if (_log.Level > 1) { _log.WriteLine( "UniAddress resolveOrder specifies WINS however the " + "jcifs.netbios.wins property has not been set"); } continue; } tmp[i++] = ResolverWins; } else { if (Runtime.EqualsIgnoreCase(s, "BCAST")) { tmp[i++] = ResolverBcast; } else { if (Runtime.EqualsIgnoreCase(s, "DNS")) { tmp[i++] = ResolverDns; } else { if (_log.Level > 1) { _log.WriteLine("unknown resolver method: " + s); } } } } } } _resolveOrder = new int[i]; Array.Copy(tmp, 0, _resolveOrder, 0, i); } } internal class Sem { internal Sem(int count) { this.Count = count; } internal int Count; } internal class QueryThread : Thread { internal Sem Sem; internal string Host; internal string Scope; internal int Type; internal NbtAddress[] Ans; internal IPAddress Svr; internal UnknownHostException Uhe; internal QueryThread(Sem sem, string host, int type, string scope, IPAddress svr) : base("JCIFS-QueryThread: " + host) { this.Sem = sem; this.Host = host; this.Type = type; this.Scope = scope; this.Svr = svr; } public override void Run() { try { //Ans = new [] { NbtAddress.GetByName(Host, Type, Scope, Svr) }; Ans = NbtAddress.GetAllByName(Host, Type, Scope, Svr); } catch (UnknownHostException uhe) { this.Uhe = uhe; } catch (Exception ex) { Uhe = new UnknownHostException(ex.Message); } finally { lock (Sem) { Sem.Count--; Runtime.Notify(Sem); } } } } /// internal static NbtAddress[] LookupServerOrWorkgroup(string name, IPAddress svr) { Sem sem = new Sem(2); int type = NbtAddress.IsWins(svr) ? unchecked(0x1b) : unchecked(0x1d); QueryThread q1X = new QueryThread(sem, name, type, null, svr); QueryThread q20 = new QueryThread(sem, name, unchecked(0x20), null, svr); q1X.SetDaemon(true); q20.SetDaemon(true); try { lock (sem) { q1X.Start(); q20.Start(); while (sem.Count > 0 && q1X.Ans == null && q20.Ans == null) { Runtime.Wait(sem); } } } catch (Exception) { throw new UnknownHostException(name); } if (q1X.Ans != null) { return q1X.Ans; } if (q20.Ans != null) { return q20.Ans; } throw q1X.Uhe; } ///

Determines the address of a host given it's host name. /// /// Determines the address of a host given it's host name. The name can be a /// machine name like "jcifs.samba.org", or an IP address like "192.168.1.15". /// /// NetBIOS or DNS hostname to resolve /// if there is an error resolving the name /// public static UniAddress GetByName(string hostname) { return GetByName(hostname, false); } internal static bool IsDotQuadIp(string hostname) { if (char.IsDigit(hostname[0])) { int i; int len; int dots; char[] data; i = dots = 0; len = hostname.Length; data = hostname.ToCharArray(); while (i < len && char.IsDigit(data[i++])) { if (i == len && dots == 3) { // probably an IP address return true; } if (i < len && data[i] == '.') { dots++; i++; } } } return false; } internal static bool IsAllDigits(string hostname) { for (int i = 0; i < hostname.Length; i++) { if (char.IsDigit(hostname[i]) == false) { return false; } } return true; } /// Lookup hostname and return it's UniAddress. /// /// Lookup hostname and return it's UniAddress. If the /// possibleNTDomainOrWorkgroup parameter is true an /// addtional name query will be performed to locate a master browser. /// /// public static UniAddress GetByName(string hostname, bool possibleNtDomainOrWorkgroup) { UniAddress[] addrs = GetAllByName(hostname, possibleNtDomainOrWorkgroup); return addrs[0]; } /// public static UniAddress[] GetAllByName(string hostname, bool possibleNtDomainOrWorkgroup) { object addr; int i; if (string.IsNullOrEmpty(hostname)) { throw new UnknownHostException(); } if (IsDotQuadIp(hostname)) { UniAddress[] addrs = new UniAddress[1]; addrs[0] = new UniAddress(NbtAddress.GetByName(hostname)); return addrs; } for (i = 0; i < _resolveOrder.Length; i++) { try { switch (_resolveOrder[i]) { case ResolverLmhosts: { if ((addr = Lmhosts.GetByName(hostname)) == null) { continue; } break; } case ResolverWins: { if (hostname == NbtAddress.MasterBrowserName || hostname.Length > 15) { // invalid netbios name continue; } if (possibleNtDomainOrWorkgroup) { addr = LookupServerOrWorkgroup(hostname, NbtAddress.GetWinsAddress()); } else { addr = NbtAddress.GetByName(hostname, unchecked(0x20), null, NbtAddress.GetWinsAddress()); } break; } case ResolverBcast: { if (hostname.Length > 15) { // invalid netbios name continue; } try { if (possibleNtDomainOrWorkgroup) { NbtAddress[] iaddrs = LookupServerOrWorkgroup(hostname, _baddr); UniAddress[] addrs = new UniAddress[iaddrs.Length]; for (int ii = 0; ii < iaddrs.Length; ii++) { addrs[ii] = new UniAddress(iaddrs[ii]); } return addrs; } else { addr = NbtAddress.GetByName(hostname, unchecked(0x20), null, _baddr); } } catch (Exception ex) { if (i == _resolveOrder.Length - 1) { throw ex; } else { continue; } } break; } case ResolverDns: { if (IsAllDigits(hostname)) { throw new UnknownHostException(hostname); } IPAddress[] iaddrs = Extensions.GetAddressesByName(hostname); if (iaddrs == null || iaddrs.Length == 0) { continue; } return iaddrs.Select(iaddr => new UniAddress(iaddr)).ToArray(); } default: { // Success throw new UnknownHostException(hostname); } } UniAddress[] addrs1 = new UniAddress[1]; addrs1[0] = new UniAddress(addr); return addrs1; } catch (IOException) { } } // Success // Failure throw new UnknownHostException(hostname); } internal object Addr; internal string CalledName; /// /// Create a UniAddress by wrapping an InetAddress or /// NbtAddress. /// /// /// Create a UniAddress by wrapping an InetAddress or /// NbtAddress. /// public UniAddress(object addr) { if (addr == null) { throw new ArgumentException(); } this.Addr = addr; } /// Return the IP address of this address as a 32 bit integer. /// Return the IP address of this address as a 32 bit integer. public override int GetHashCode() { return Addr.GetHashCode(); } /// Compare two addresses for equality. /// /// Compare two addresses for equality. Two UniAddresss are equal /// if they are both UniAddress' and refer to the same IP address. /// public override bool Equals(object obj) { return obj is UniAddress && Addr.Equals(((UniAddress)obj).Addr); } /// Guess first called name to try for session establishment. /// /// Guess first called name to try for session establishment. This /// method is used exclusively by the jcifs.smb package. /// public virtual string FirstCalledName() { if (Addr is NbtAddress) { return ((NbtAddress)Addr).FirstCalledName(); } CalledName = ((IPAddress)Addr).GetHostAddress(); if (IsDotQuadIp(CalledName)) { CalledName = NbtAddress.SmbserverName; } else { int i = CalledName.IndexOf('.'); if (i > 1 && i < 15) { CalledName = Runtime.Substring(CalledName, 0, i).ToUpper(); } else { if (CalledName.Length > 15) { CalledName = NbtAddress.SmbserverName; } else { CalledName = CalledName.ToUpper(); } } } return CalledName; } /// Guess next called name to try for session establishment. /// /// Guess next called name to try for session establishment. This /// method is used exclusively by the jcifs.smb package. /// public virtual string NextCalledName() { if (Addr is NbtAddress) { return ((NbtAddress)Addr).NextCalledName(); } if (CalledName != NbtAddress.SmbserverName) { CalledName = NbtAddress.SmbserverName; return CalledName; } return null; } /// Return the underlying NbtAddress or InetAddress. /// Return the underlying NbtAddress or InetAddress. public virtual object GetAddress() { return Addr; } /// Return the hostname of this address such as "MYCOMPUTER". /// Return the hostname of this address such as "MYCOMPUTER". public virtual string GetHostName() { if (Addr is NbtAddress) { return ((NbtAddress)Addr).GetHostName(); } return ((IPAddress)Addr).GetHostAddress(); } /// Return the IP address as text such as "192.168.1.15". /// Return the IP address as text such as "192.168.1.15". public virtual string GetHostAddress() { if (Addr is NbtAddress) { return ((NbtAddress)Addr).GetHostAddress(); } return ((IPAddress)Addr).GetHostAddress(); } public virtual IPAddress GetHostIpAddress() { return (IPAddress)Addr; } /// /// Return the a text representation of this address such as /// MYCOMPUTER/192.168.1.15. /// /// /// Return the a text representation of this address such as /// MYCOMPUTER/192.168.1.15. /// public override string ToString() { return Addr.ToString(); } } }