1
2 """
3 This library can be used to retrieve network and TCP information, such as getting the Operating
4 system name, checking if a MAC Address is valid, check if an IP Address is valid etc.
5 """
6
7 from java.net import InetAddress, URL
8 from java.net import Socket
9 from java.net import InetSocketAddress
10 from java.net import SocketTimeoutException
11 from java.lang import Exception as JException
12 from java.io import IOException
13 from java.util import Properties
14 from appilog.common.utils import IPv4
15 from org.apache.commons.httpclient.methods import GetMethod, HeadMethod
16 from org.apache.commons.httpclient import HttpClient
17 from com.hp.ucmdb.discovery.library.communication.downloader.cfgfiles import (
18 KnownPortsConfigFile, PortInfo)
19 from com.hp.ucmdb.discovery.library.clients import ClientsConsts
20 from com.ziclix.python.sql import PyConnection
21 from java.lang import Class, Thread
22 from java.net import UnknownHostException
23
24 import logger
25 import re
26 import sys
27 import string
28 from appilog.common.system.types import ObjectStateHolder
29 import ip_addr
30
31
33 """
34 Resolves the host name to the IP Address in DNS table.
35 On failure to resolve the name, the default value parameter is returned.
36 @param dnsName: host name to resolve
37 @type dnsName: string
38 @param defaultValue: the value to return if the host name cannot be resolved
39 @return: IP address of the resolved host name
40 @rtype: string
41 """
42 if dnsName and dnsName.strip():
43 try:
44 return str(InetAddress.getByName(dnsName).getHostAddress())
45 except:
46 logger.debugException('Could not resolve DNS name: ', dnsName)
47 return defaultValue
48
49
51 """
52 Resolves the IP address to the host name in the DNS table.
53 On failure to resolve the address the , default value parameter is returned.
54 @param ipAddress: IP address to resolve
55 @type ipAddress: string
56 @param defaultValue: the value to return if the address cannot be resolved
57 @return: host name of the resolved IP address
58 @rtype: string
59 """
60 if isValidIp(ipAddress):
61 try:
62 dnsName = str(InetAddress.getByName(ipAddress).getHostName())
63 if dnsName == ipAddress:
64 return defaultValue
65 else:
66 return dnsName
67 except:
68 defultHostName = defaultValue
69 if defultHostName == None:
70 defultHostName = 'null'
71 logger.debug('Could not resolve DNS name for : ', ipAddress,
72 ',returning default value:', defultHostName,
73 ';reason:', str(sys.exc_info()[1]))
74 return defaultValue
75
76
78 """
79 Checks whether the given IP address is valid.
80 @param ipAddr: IP address to check
81 @type ipAddr: string
82 @return: true if the IP is valid, else false
83 @rtype: Boolean
84 """
85
86
87 if ipAddr and ipAddr.strip() == '255.255.255.255':
88 return None
89 return IPv4.isValidIp(ipAddr)
90
91
93 """
94 Converts chars in given string from hex codes to ascii symbols
95 e.g. '4A415641' -> 'JAVA'
96 @param asciiSeq: hex string for conversion
97 @rtype: string
98 @note: Don't be frustrated by the name of function!
99 '4A415641' - is ascii codes; returned value 'JAVA' - is a hex string
100 """
101 seq = list(asciiSeq)
102 return ''.join([chr(int(''.join(l), 16)) for l in zip(seq[0::2], seq[1::2])])
103
104
106 """
107 Parses the given macAddress and converts it to the system format I{XXXXXXXXXXXX},
108 where X is an uppercase hexadecimal digit.
109 @param origmac: raw or formated MAC address
110 @type origmac: string
111 @return: parsed MAC address in the converted format
112 @rtype: string
113 @raise ValueError: If address has invalid format
114 """
115 if origmac.isdigit() and len(origmac) > 12:
116 origmac = convertAsciiCodesToHex(origmac)
117
118
119
120 mac = origmac.strip().upper()
121
122
123 mac = mac.replace('0X', '')
124
125 macRe = r'\A([0-9A-F]{1,2}[-]?){4,8}\Z|\A([0-9A-F]{1,2}[:]?){4,8}\Z'
126 m = re.search(macRe, mac)
127 if m:
128 compactedParts = re.findall('[0-9A-F]{1,2}', mac)
129 compactedMac = ''
130 for part in compactedParts:
131 if len(part) == 1:
132 part = '0%s' % part
133 compactedMac += part
134 if (len(compactedMac) in (8, 12, 16)):
135 return compactedMac
136
137 raise ValueError('Failed parsing MAC address: ' + origmac)
138
139
140 _IGNORED_INTERFACE_MACS = ("204153594EFF", "33506F453030", "505054503030", "444553540000", "444553544200", "001986002B48", "020054554E01", "7A7700000001",\
141 "BAD0BEEFFACE", "00F1D000F1D0", "80000404FE80", "000613195800", "7A8020000200", "FEFFFFFFFFFF", "028037EC0200", "8000600FE800",\
142 "0200CAFEBABE", "020054746872", "000FE207F2E0", "020255061358", "080058000001", "000419000001", "002637BD3942", "025041000001",\
143 "009876543210", "582C80139263", "00ADE1AC1C1A", "02004C4F4F50", "444553547777")
144
145 _IGNORED_INTERFACE_MAC_PATTERNS = ('^0{6}', '0{6}$', 'F{12}', '^00FF[\dA-F]{8}', '^0250F200000[\dA-F]', '^000AFA020[\dA-F]00', '^00E00900000[\dA-F]',\
146 '^02BF[\dA-F]{8}', '^5455434452[\dA-F]{2}', '^020000000[\dA-F]{3}', '^00A0D5FFFF[\dA-F]{2}', '^005056C0000[\dA-F]',\
147 '^00059A3C7[\dA-F]00', '^001C4200000[\dA-F]')
148
150 """
151 Checks whether the specified MAC address is valid.
152 @param mac: MAC address to check
153 @type mac: string
154 @return: 1 if MAC is valid, 0 otherwise
155 @rtype: integer
156 """
157 if ifType != 'ethernetCsmacd':
158 return 0
159 try:
160 mac = parseMac(mac)
161
162
163 if mac in _IGNORED_INTERFACE_MACS:
164 logger.warn('Interface with MAC: %s is ignored as it\'s in the ignored list' % mac)
165 return 0
166 for ignorePattern in _IGNORED_INTERFACE_MAC_PATTERNS:
167 if re.search(ignorePattern, mac):
168 return 0
169 return 1
170 except:
171 return 0
172
173
175 """
176 Parses the supplied network mask into the common format of %d.%d.%d.%d
177 @param origmask: NetMask address to parse
178 @type origmask: string
179 @return: parsed NetMask address
180 @rtype: string
181 """
182
183
184 mask = string.strip(origmask)
185
186
187 mask = string.upper(mask)
188
189
190 if(re.match('[0-9A-F]{8}\s*', mask)):
191 nmask = ''
192 m = re.match('(..)(..)(..)(..)', mask)
193 for i in range(4):
194 x = m.group(i + 1)
195 nmask = nmask + str(int(x, 16))
196 if(i != 3):
197 nmask = nmask + '.'
198
199 mask = nmask
200
201 if(re.match('\d+\.\d+\.\d+\.\d+', mask)):
202 return mask
203 else:
204 raise Exception('Failed to parse invalid network mask: ' + origmask)
205
206
208
209 """
210 Retrieves the operating system name.
211 @param client: pre-connected shell client
212 @type client: shellClinet
213 @return: operating system name
214 @rtype: string
215 """
216 r = client.executeCmd(cmd)
217 if r == None:
218 return ''
219 osname = ''
220 if(re.search('Microsoft Windows', r)):
221 osname = 'Windows'
222 else:
223 lines = r.split('\n')
224 uname = ''
225 for line in lines:
226 if(not re.search('uname', line)):
227 uname = line
228 break
229 if(len(uname) < 3):
230 osname = ''
231 else:
232 token = string.split(uname)
233 os_name = token[0]
234 if(re.search('SunOS', os_name)):
235 osname = 'SunOS'
236 elif(re.search('Linux', os_name)):
237 osname = 'Linux'
238 elif(re.search('FreeBSD', os_name)):
239 osname = 'FreeBSD'
240 elif(re.search('HP-UX', os_name)):
241 osname = 'HP-UX'
242 elif(re.search('AIX', os_name)):
243 osname = 'AIX'
244 elif re.search('VMkernel', os_name):
245 osname = 'VMkernel'
246 elif re.search('Darwin', os_name):
247 osname = 'MacOs'
248 elif re.search('OpenBSD', os_name):
249 osname = 'OpenBSD'
250 else:
251 logger.debug('unknown OS: ' + os_name)
252 osname = ''
253 if osname == '':
254 if r.find('SunOS') != -1:
255 osname = 'SunOS'
256 elif r.find('Linux') != -1:
257 osname = 'Linux'
258 elif r.find('FreeBSD') != -1:
259 osname = 'FreeBSD'
260 elif r.find('HP-UX') != -1:
261 osname = 'HP-UX'
262 elif r.find('AIX') != -1:
263 osname = 'AIX'
264 elif r.find('VMkernel') != -1:
265 osname = 'VMkernel'
266 elif r.find('Darwin') != -1:
267 osname = 'MacOs'
268 elif r.find('OpenBSD') != -1:
269 osname = 'OpenBSD'
270 else:
271 logger.debug('unknown OS: ' + r)
272 return osname
273
274
276 """
277 Checks whether the specified IP is loopback (assumes the given IP is *valid*).
278 Loopback IPs are any IP which starts with '127.'
279 @param ip: IP address to check
280 @type ip: String
281 @return: 1 if the IP is loopback, else 0
282 @rtype: int
283 """
284 return ip.startswith('127.')
285
286
288 """
289 Checks whether the specified IP is local (assumes the given IP is *valid*).
290 Local IPs are any IP which starts with '127.' or '0.'
291 @param ip: IP address to check
292 @type ip: String
293 @return: 1 if the IP is local, else 0
294 @rtype: int
295 """
296 return ip.startswith('0.') or ip.startswith('127.')
297
298
300 """
301 Checks is the specified IP belongs to private network (assumes the given IP is *valid*).
302 Private IP addresses described in RFC 1918 (Private Address Space section)
303 They are:
304 10.0.0.0 - 10.255.255.255 (10/8 prefix)
305 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
306 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
307 @param ip: IP address to check
308 @type ip: String
309 @return: 1 if the IP belongs to private network, else 0
310 @rtype: int
311 """
312 if ip.startswith('10.') or ip.startswith('192.168.'):
313 return 1
314 low_172_ip = convertIpToInt('172.16.0.0')
315 high_172_ip = convertIpToInt('172.31.255.255')
316 int_ip = convertIpToInt(ip)
317 return low_172_ip <= int_ip <= high_172_ip
318
319
321 """
322 Returns available protocols of desired type defined in domain scope
323 document for concrete IP
324 """
325 protocols = Framework.getAvailableProtocols(IP, PROT_TYPE)
326 preferredCredId = Framework.loadState()
327 if preferredCredId is not None and preferredCredId in protocols:
328 tmp = [preferredCredId]
329 for protocol in protocols:
330 if protocol != preferredCredId:
331 tmp.append(protocol)
332 protocols = tmp
333 return protocols
334
335
337 '''
338 Resolves fqdn of a host by ip.
339 NsLookup is used first and then @netutils.getHostName used on fallback
340
341 Shell, ip -> str or None
342 '''
343 dnsResolver = DNSResolver(shell)
344 fqdn = dnsResolver.resolveDnsNameByNslookup(ip)
345 if not fqdn:
346 fqdn = getHostName(ip)
347 return fqdn
348
349
351 '''
352 Resolves ip address of a host by its name(dns)
353 NsLookup is used first and then destinations' hosts file on fallback
354 Shell, str -> str or None
355 '''
356
357 dnsResolver = DNSResolver(shell)
358 ip = None
359 try:
360 ips = dnsResolver.resolveIpByNsLookup(hostName)
361 ip = ips and ips[0] or dnsResolver.resolveHostIpByHostsFile(hostName)
362 except:
363 logger.warn('Failed to resolve host ip throught nslookup')
364
365 if not ip:
366 ip = getHostAddress(hostName)
367 return ip
368
369
371 '''
372 Checks whether url is available
373 str, list(str), int -> bool
374 '''
375 from com.hp.ucmdb.discovery.library.clients import (
376 ApacheHttpClientWrapper as HttpClientWrapper, SSLContextManager)
377
378 if not url or not acceptedStatusCodeRange:
379 return 0
380 client = HttpClientWrapper()
381 client.setSocketTimeout(timeout)
382 try:
383 jurl = URL(url)
384 if jurl.getProtocol() == 'https':
385 port = jurl.getPort() or HttpClientWrapper.DEFAULT_HTTPS_PORT
386 context = SSLContextManager.getAutoAcceptSSLContext()
387 client.registerProtocol(context, port)
388 except:
389 logger.warn('Failed parsing url % ' % url)
390 try:
391 httpResult = client.get(url)
392 return httpResult.statusCode in acceptedStatusCodeRange
393 except:
394 logger.warn('Get Failed: %s' % logger.prepareJavaStackTrace())
395
396 return 0
397
398
399 -def doHttpGet(url, timeout=20000, requestedData='body', headerName=None):
400 """
401 Performs HTTP(S) Connection to the specified URL
402
403 Returns data according to the requestedData flag:
404 'body': Full Response Body as String
405 'header': Returns the response header with the specified headerName
406 """
407 if requestedData == 'header':
408 method = HeadMethod(url)
409 else:
410 method = GetMethod(url)
411 client = HttpClient()
412 client.getHttpConnectionManager().getParams().setConnectionTimeout(timeout)
413 client.getHttpConnectionManager().getParams().setSoTimeout(timeout)
414 client.executeMethod(method)
415
416 if (requestedData == 'body'):
417 return method.getResponseBodyAsString()
418 elif (requestedData == 'header'):
419 if headerName:
420 return method.getResponseHeader(headerName)
421 else:
422 result = method.getResponseHeaders()
423 return ''.join([s.toString() for s in result])
424 else:
425 raise ValueError('Response part %s in not supported' % requestedData)
426
427
429 """
430 Checks the TCP connection to the given ipAddress on the given port.
431 @param ipAddress: IP address of the remote computer to check
432 @type ipAddress: String
433 @param portNumber: The port number to check
434 @type portNumber: int
435 @param timeout: connection timeout in millisecondes
436 @type timeout: int
437 @return 1 if the TCP connection succeeded, else
438 """
439 socket = None
440 try:
441 socket = Socket()
442 socket.connect(InetSocketAddress(ipAddress, portNumber), timeout)
443 logger.debug('Connected to port:', portNumber, ' on host by ip:',
444 ipAddress)
445
446 if (socket != None):
447 try:
448
449 socket.close()
450 except:
451
452 logger.debug('Failed to close socket')
453 return 1
454 except IOException, e:
455 logger.debug('Failed to connect to port:', portNumber,
456 ' on host by ip:', ipAddress,
457 ' IOException(', e.getMessage(), ')')
458 return 0
459 except SocketTimeoutException, e:
460 logger.debug('Failed to connect to port:', portNumber,
461 ' on host by ip:', ipAddress,
462 ' SocketTimeoutException(', e.getMessage(), ')')
463 return 0
464
465
466 -def pingIp(Framework, ipAddress, timeout):
467 """
468 Ping the specified device
469 @param ipAddress: the IP address to ping
470 @type ipAddress: string
471 @param timeout: ping timeout in milliseconds
472 @type timeout: int
473 @return: 1 if the machine is pingable, else 0
474 """
475 properties = Properties()
476 properties.setProperty('timeoutDiscover', timeout)
477 properties.setProperty('retryDiscover', '1')
478 client = Framework.createClient(ClientsConsts.ICMP_PROTOCOL_NAME, properties)
479 _ipForICMPList = []
480 _ipForICMPList.append(ipAddress)
481 res = client.executePing(_ipForICMPList)
482 if (res == None) or len(res) == 0:
483
484 return 0
485
486 return 1
487
488
490 """
491 Checks whether the given IP is a broadcast IP
492 @param ipAddress: IP address to check
493 @type ipAddress: string
494 @param netmask: corresponding IP network mask
495 @type netmask: string
496 @return: boolean
497 """
498 bcast = None
499 if ipAddress and netmask and isValidIp(ipAddress):
500 netMask = parseNetMask(netmask)
501 parsedIp = IPv4(ipAddress, netMask)
502 if netMask != "255.255.255.255" and netMask != "255.255.255.254":
503 broadcastIp = parsedIp.getLastIp()
504 if parsedIp == broadcastIp:
505 bcast = 1
506 return bcast
507
508
510 """
511 Checks whether the given IP is anycast
512 Anycast is a network addressing and routing scheme whereby data is routed
513 to the "nearest" or "best" destination as viewed by the routing topology
514 Can be obtained in following way: non-local IP on loop-back interface
515 @param ipAddress: IP address to check
516 @type ipAddress: string
517 @param interfaceName: name of the network interface
518 @type interfaceName: string
519 """
520 return (ipAddress
521 and interfaceName
522 and (re.match('lo.*', interfaceName, re.IGNORECASE)
523 or re.search('.*Loopback.*', interfaceName))
524 and not isLocalIp(ipAddress))
525
526
528 """
529 Return port name for the given port number and type.
530 @param portNumber: The port number
531 @param portType: The port type (TCP / UDP)
532 @return: String the description
533 """
534 return KnownPortsConfigFile.GetPortNameByNumberAndType(str(portNumber),
535 portType, "")
536
537
539 """
540 Return PyConnection to the database (see Jython's zxJDBC description)
541 @param userName: the username to connect to DB with
542 @param password: the password to connect to DB with
543 @param driverName: name of the driver to connect through
544 @return: com.ziclix.python.sql.PyConnection
545 """
546 jdbcDriver = Class.forName(driverName, 1,
547 Thread.currentThread().getContextClassLoader()).newInstance()
548 props = Properties()
549 props.put('user', userName)
550 props.put('password', password)
551 return PyConnection(jdbcDriver.connect(connectionURL, props))
552
553
555 """
556 Returns the count of 1 in binary representation of given number
557 @type number: integer
558 @rtype: integer
559 """
560 if number > 0:
561 return (number % 2) + getLeadingOnesCount(number >> 1)
562 else:
563 return 0
564
565
567 """
568 Returns the count of set bit in given network mask
569 e.g. for mask '255.255.255.0' return value will be 24
570 @type netmask: string
571 @rtype: integer
572 """
573 shortMask = 0
574 if IPv4.isValidIp(netmask):
575 octets = netmask.split('.')
576 for octet in octets:
577 shortMask += getLeadingOnesCount(int(octet))
578 return shortMask
579
580
582 '''
583 @precondition: IpV6 is not supported
584 Decode routing prefix to IpV4 (dotDecimal) mask or IpV6 mask
585 @param routingPrefix: routing prefix - natural numbers
586 @param isIpV4: if true dot-decimal mask will be used instead of IpV6
587 @return: subnet mask
588 @rtype: string
589 '''
590 if not routingPrefix in range(0, 33):
591 raise ValueError('routingPrefix should be in 0..32 range for ipV4')
592
593 subNetMask = None
594 if isIpV4:
595 routingPrefix = int(routingPrefix)
596 bitStr = '%s%s' % ('1' * routingPrefix, '0' * (32 - routingPrefix))
597 iByte = 8
598 octets = []
599 for i in xrange(0, len(bitStr), iByte):
600 octet = bitStr[i: i + iByte]
601 octets.append(int(octet, 2))
602 subNetMask = ('%s.%s.%s.%s' % tuple(octets))
603 else:
604 raise Exception('IpV6 mask decoding is not implemented')
605 return subNetMask
606
607
609 '''
610 @precondition: only IPv4 is supported
611 Obtain subnet mask from cidr notation.
612 @param cidrNotationAddress: address string in CIDR notation (xxx.xxx.xxx.xxx/xx)
613 @return: subnet mask in dot-decimal notation or None
614 @rtype: string
615 '''
616 result = None
617
618 if cidrNotationBlock and cidrNotationBlock.count('/'):
619 (ip, prefix) = cidrNotationBlock.split('/')
620 result = (prefix.isdigit()
621 and (ip, decodeSubnetMask(int(prefix)))
622 or None)
623 return result
624
625
627 """
628 Transforms IP address from string representation to numeric
629 @param ipString: given IP or network mask to transform
630 @type ipString: string
631 @rtype: integer
632 """
633 return reduce(lambda value, token:
634 value * 256 + long(token), ipString.split('.'), 0)
635
636
638 """
639 Getting minimal IP from list of IPs
640 @note: if list of local IPs passed return the latest one
641 @param listIp: list of IPs from which need to find minimal
642 @type listIp: list(str)
643 @rtype: str
644 @raise ValueError: list of IPs is empty
645 """
646 if listIp:
647 smallIp = None
648 intSmallIp = convertIpToInt('255.255.255.255')
649 for ip in filter(None, listIp):
650 ip = ip.strip()
651 latestLocalIp = None
652
653 if isLocalIp(ip):
654 latestLocalIp = ip
655
656
657 if not isLocalIp(ip) and convertIpToInt(ip) < intSmallIp:
658
659 smallIp = ip
660 intSmallIp = convertIpToInt(smallIp)
661
662
663 result = smallIp or latestLocalIp
664
665 if result == '255.255.255.255':
666 raise ValueError('Passed list does not contain valid IPs')
667
668 return result
669 raise ValueError('Passed empty list of IPs')
670
671
673 """
674 Basing on integer representation of network mask returns MAXIMAL count of
675 IPs which can be addressed in given network
676 @param mask: network mask in integer representation
677 @type mask: integer
678 @see: convertIpToInt
679 @rtype: integer
680 """
681 negvalue = ~(0)
682 for i in xrange(32 - getLeadingOnesCount(mask)):
683 negvalue = negvalue << 1
684 return long(~negvalue)
685
686
693
694
696 if networkPrefix is not None:
697 if networkPrefix >= 24:
698 return "C"
699 if networkPrefix >= 16:
700 return "B"
701 if networkPrefix >= 8:
702 return "A"
703 return None
704
705
713
714
716 'Identify port type in application layer of OSI'
719
721 r'@types: -> str'
722 return self.__name
723
725 r'@types: _PortType -> bool'
726 return (other and isinstance(other, _PortType)
727 and self.getName() == other.getName())
728
730 r'@types: _PortType -> bool'
731 return not self.__eq__(other)
732
735
737 return '_PortType(%s)' % self.__name
738
740 return hash(self.__name)
741
742
745
746
747 if filter(lambda pt: not isinstance(pt, _PortType), portTypes.values()):
748 raise ValueError("Value of wrong type specified")
749 self.__portTypeByName = portTypes
750
752 value = self.__portTypeByName.get(name)
753 if value:
754 return value
755 raise AttributeError
756
758 r'@types: _PortType -> bool'
759 return self.__portTypeByName.values().count(portType) > 0
760
761 - def merge(self, otherEnum):
762 r'@types: _PortTypeEnum -> _PortTypeEnum'
763 if not isinstance(otherEnum, _PortTypeEnum):
764 raise ValueError("Wrong enum type")
765 extended = self.items().copy()
766 extended.update(otherEnum.items())
767 return _PortTypeEnum(**extended)
768
770 return self.__portTypeByName.copy()
771
773 r'@types: -> list[_PortType]'
774 return self.__portTypeByName.values()
775
777 r''' Find port type by name
778 @types: str -> _PortType or None'''
779 if signature:
780 for pt in self.values():
781 if signature.strip().lower() == pt.getName():
782 return pt
783
784 PortTypeEnum = _PortTypeEnum(
785 HTTP=_PortType('http'),
786 HTTPS=_PortType('https'),
787 SNMP=_PortType('snmp'),
788 SMTP=_PortType('smpt'))
789
790
792 - def __init__(self, port, protocol, address, isListen=0, portType=None):
793 r'''@types: number, ProtocolType, str, bool, _PortType
794 @raise ValueError: Port is not specified
795 @raise ValueError: Protocol is incorrect
796 @raise ValueError: Address is not specified
797 '''
798 exec("import entity")
799 self.__port = entity.Numeric(int)
800 self.__port.set(port)
801
802 if not protocol in ProtocolType().values():
803 raise ValueError("Protocol is incorrect")
804 self.__protocol = protocol
805
806 if not (address and str(address).strip()):
807 raise ValueError("Address is not specified")
808 self.__address = address
809 self.__isListen = isListen
810 self.__portType = portType
811
813 r'''@types: -> int'''
814 return self.__port.value()
815
817 r'@types: -> str'
818 return self.__address
819
821 r'@types: -> bool'
822 return self.__isListen
823
825 r'@types: -> _PortType'
826 return self.__portType
827
829 r'@types: -> int'
830 return self.__protocol
831
834
843
845 return not self.__eq__(other)
846
849
850
854
855
860
861
864 r'@types: object, list[netutils.Endpoint]'
865 if key is not None:
866 self.__key = key
867 else:
868 raise ValueError("key is empty or None")
869 if endPointList:
870 self.__endPointList = endPointList
871 else:
872 raise ValueError("endPointList is None")
873
876
878 return self.__endPointList
879
880
882 r'Base builder for endpoint as we have two types: URI and IP service endpoint'
884 r'@types: netutils.Endpoint -> ObjectStateHolder'
885 raise NotImplementedError()
886
887
890 r'@types: netutils.Endpoint -> ObjectStateHolder'
891 osh = ObjectStateHolder('uri_endpoint')
892 uri = "%s:%s" % (endpoint.getAddress(), endpoint.getPort())
893 osh.setAttribute('uri', uri)
894 return osh
895
896
899 r'''
900 @types: netutils.Endpoint -> ObjectStateHolder
901 @raise ValueError: Not supported protocol type
902 @raise ValueError: Invalid IP address
903 '''
904 address = endpoint.getAddress()
905 if not isinstance(address, (ip_addr.IPv4Address, ip_addr.IPv6Address)):
906 address = ip_addr.IPAddress(address)
907 ipServerOSH = ObjectStateHolder('ipserver')
908 uri = "%s:%s" % (address, endpoint.getPort())
909 ipServerOSH.setAttribute('ipserver_address', uri)
910 ipServerOSH.setAttribute('ipport_number', endpoint.getPort())
911 if endpoint.getProtocolType() == ProtocolType.TCP_PROTOCOL:
912 portType = ('tcp', 1)
913 elif endpoint.getProtocolType() == ProtocolType.UDP_PROTOCOL:
914 portType = ('udp', 2)
915 else:
916 raise ValueError("Not supported protocol type")
917 ipServerOSH.setAttribute('port_type', portType[0])
918 ipServerOSH.setEnumAttribute('ipport_type', portType[1])
919 ipServerOSH.setAttribute('ip_address', str(address))
920 if endpoint.getPortType():
921 ipServerOSH.setStringAttribute('data_name', str(endpoint.getPortType()))
922 return ipServerOSH
923
924
927 r'@types: EndpointBuilder'
928 if not builder:
929 raise ValueError("Endpoint builder is not specified")
930 self.__builder = builder
931
933 r'''@types: Endpoint, ObjectStateHolder -> ObjectStateHolder
934 @raise ValueError: Endpoint is not specified
935 @raise ValueError: Container is not specified
936 '''
937 if not endpoint:
938 raise ValueError("Endpoint is not specified")
939 if not containerOsh:
940 raise ValueError("Container is not specified")
941 osh = self.__builder.visitEndpoint(endpoint)
942 osh.setContainer(containerOsh)
943 return osh
944
946 r'''@types: Endpoint -> ObjectStateHolder
947 @raise ValueError: Endpoint is not specified
948 @raise ValueError: Invalid IP address
949 '''
950 if not endpoint:
951 raise ValueError("Endpoint is not specified")
952 if not isValidIp(endpoint.getAddress()):
953 raise ValueError("Invalid IP address")
954 exec("import modeling")
955 return modeling.createHostOSH(endpoint.getAddress())
956
957
958 WINDOWS_HOSTS_CONFIG = '%SystemRoot%\system32\drivers\etc\hosts'
959 UNIX_HOSTS_CONFIG = '/etc/hosts'
960
961
963 """
964 Class responsible for getting nslookup results on a client's machine
965 """
968
970 """
971 Resolves (or not) IP addresses by given machine name
972 @param dnsName: the machine name to resolve IPs
973 @type dnsName: string
974 @rtype: list
975 """
976 from shellutils import WinShell
977 if dnsName:
978 currentCodePage = WinShell.DEFAULT_ENGLISH_CODEPAGE
979 ipAddressList = []
980 if self.shell.isWinOs():
981 currentCodePage = self.shell.getCodePage()
982 if currentCodePage != WinShell.DEFAULT_ENGLISH_CODEPAGE:
983 self.shell.setCodePage(WinShell.DEFAULT_ENGLISH_CODEPAGE)
984 try:
985 buffer = self.shell.execCmd('nslookup %s' % dnsName, useCache=1)
986 if buffer.find('can\'t find') == -1 and self.shell.getLastCmdReturnCode() == 0:
987 matchPat = ".*Name:\s+" + dnsName + ".*\n\s*Addresses:\s*(.*)"
988 rawAddr = re.search(matchPat, buffer, re.S)
989 if not rawAddr:
990 matchPat = ".*Name:\s+" + dnsName + ".*\n\s*Address:\s*(.*)"
991 rawAddr = re.search(matchPat, buffer, re.S)
992 if rawAddr:
993 lines = re.split('[,\s]+', rawAddr.group(1).strip())
994 if lines:
995 for line in lines:
996 if line and isValidIp(line.strip()):
997 ipAddressList.append(line.strip())
998 finally:
999 if self.shell.isWinOs() and currentCodePage != WinShell.DEFAULT_ENGLISH_CODEPAGE:
1000 self.shell.setCodePage(currentCodePage)
1001 return ipAddressList
1002
1029
1031 """
1032 Resolves (or not) machine DNS name by given IP
1033 @param dnsName: the machine name to resolve IPs
1034 @type dnsName: string
1035 @rtype: string
1036 @return: IP address if resolved; None if not resolved
1037 """
1038 if ipAddr:
1039 from shellutils import WinShell
1040 currentCodePage = WinShell.DEFAULT_ENGLISH_CODEPAGE
1041 if self.shell.isWinOs():
1042 currentCodePage = self.shell.getCodePage()
1043 if currentCodePage != WinShell.DEFAULT_ENGLISH_CODEPAGE:
1044 self.shell.setCodePage(WinShell.DEFAULT_ENGLISH_CODEPAGE)
1045 try:
1046 buffer = self.shell.execCmd('nslookup %s %s' % (ipAddr, dnsServer))
1047 finally:
1048 if self.shell.isWinOs() and currentCodePage != WinShell.DEFAULT_ENGLISH_CODEPAGE:
1049 self.shell.setCodePage(currentCodePage)
1050 if buffer.find('can\'t find') == -1 and self.shell.getLastCmdReturnCode() == 0:
1051 matchPat = ".*Name:\s+(.*?)\n"
1052 dnsName = re.search(matchPat, buffer, re.S)
1053 if not dnsName:
1054 matchPat = ".*arpa\s+name\s*=\s*(.*?)\.\s*\n"
1055 dnsName = re.search(matchPat, buffer, re.S)
1056 if dnsName:
1057 return dnsName.group(1).strip()
1058
1060 """
1061 Resolves (or not) machine DNS name by given IP using system's "hosts" file
1062 @param dnsName: the machine name to resolve IPs
1063 @type dnsName: string
1064 @rtype: string
1065 @return: IP address if resolved; None if not resolved
1066 """
1067 cmd = None
1068 if self.shell.isWinOs():
1069 cmd = WINDOWS_HOSTS_CONFIG
1070 else:
1071 cmd = UNIX_HOSTS_CONFIG
1072 if dnsName:
1073 buffer = self.shell.safecat(cmd)
1074 if buffer and self.shell.getLastCmdReturnCode() == 0:
1075 for line in buffer.split('\n'):
1076 ipaddr = re.search(r"\s*(\d+\.\d+\.\d+.\d*).*\s" + dnsName + "[\s\.].*", line)
1077 if ipaddr:
1078 return ipaddr.group(1).strip()
1079
1080
1082 """
1083 Class responsible for resolving IP addresses on probe machine's side
1084 """
1085 - def __init__(self, remoteDnsAddress, framework):
1086 self.remoteDnsAddress = remoteDnsAddress
1087 self.framework = framework
1088 self.localShell = None
1089
1091 """
1092 Resolves (or not) IP address by given machine name
1093 @param hostName: the machine name to resolve IPs
1094 @type hostName: string
1095 @rtype: string
1096 """
1097 try:
1098 return InetAddress.getByName(hostName).getHostAddress()
1099 except UnknownHostException:
1100 pass
1101
1103 """
1104 Resolves (or not) IP address by given machine name using nslookup command on probe machine
1105 @param hostName: the machine name to resolve IP
1106 @type hostName: string
1107 @param remoteDns: the remate DNS name (or IP) to resolve host IP
1108 @type remoteDns: string
1109 @rtype: string
1110 """
1111 if not self.localShell:
1112 self.localShell = self.getLocalShell()
1113 if self.localShell:
1114 command = "nslookup %s %s" % (hostName, remoteDns)
1115 output = self.localShell.executeCmd(command)
1116 if output:
1117 pattern = "Name:\s+%s(?:\.[\w\.-]+)?\s*Address(?:es)?:\s*([\d\.\,\s]+)" % re.escape(hostName)
1118 matcher = re.search(pattern, output, re.I)
1119 if matcher:
1120 resolvedIpsString = matcher.group(1)
1121 resolvedIps = resolvedIpsString.split(',')
1122 resolvedIp = None
1123 try:
1124 resolvedIp = getLowestIp(resolvedIps)
1125 except:
1126 logger.warnException('Failed to find a minimal IP in the %s' % resolvedIps)
1127 if resolvedIp is not None:
1128 if isValidIp(resolvedIp) and not isLocalIp(resolvedIp):
1129 return resolvedIp
1130
1132 """
1133 Tries to resolve host IP using resolveHostIpWithLocalDns and resolveHostIpWithRemoteDns
1134 methods (in fall-back order)
1135 @param hostName: the machine name to resolve IP
1136 @type hostName: string
1137 @rtype: string
1138 """
1139 resultIp = self.resolveHostIpWithLocalDns(hostName)
1140 if not resultIp:
1141 resultIp = self.resolveHostIpWithRemoteDns(hostName, self.remoteDnsAddress)
1142 if not resultIp:
1143 logger.debug("Failed to resolve IP for host '%s'" % hostName)
1144 return resultIp
1145
1147 """
1148 Creates and caches local shell client.
1149 Must not be used outside of class.
1150 """
1151 try:
1152 return self.framework.createClient(ClientsConsts.LOCAL_SHELL_PROTOCOL_NAME)
1153 except:
1154 logger.errorException('Failed to create LocalShell client')
1155
1157 """
1158 Closes local shell client.
1159 Have to be called after usage of IpResolver
1160 """
1161 if self.localShell is not None:
1162 try:
1163 self.localShell.close()
1164 self.localShell = None
1165 except:
1166 pass
1167
1168
1170 r'''Base exception class used for DNS resolving'''
1171 pass
1172
1173
1175 'Base class for DNS resolvers'
1176
1177 _HOSTNAME_RESOLVE_EXCEPTION = ResolveException('Failed to resolve hostname')
1178 _IP_RESOLVE_EXCEPTION = ResolveException('Failed to resolve IP')
1179
1181 '''@types: str -> list[str]
1182 @raise ResolveException: Failed to resolve hostname
1183 '''
1184 raise NotImplementedError()
1185
1187 '''@types: str -> list[str]
1188 @raise ResolveException: Failed to resolve IP
1189 '''
1190 raise NotImplementedError()
1191
1192
1194 '''
1195 Implementation of DNS resolving using fallback approach against different resolvers
1196 '''
1197
1199 self.__resolvers = resolvers
1200
1202 '''
1203 Call for each resolver resolveHostnamesByIp and if it was failed with ResolveException,
1204 call next resolver
1205
1206 @types: method, *args -> list(str)
1207 @param: method - method wich will be call for each resolver
1208 @param: *args - arguments for the method
1209 '''
1210
1211 for resolver in self.__resolvers:
1212 try:
1213 return resolver.resolveHostnamesByIp(ip)
1214 except ResolveException, re:
1215 logger.warn(str(re))
1216 raise self._HOSTNAME_RESOLVE_EXCEPTION
1217
1219 '''
1220 Call for each resolver method and if it was failed with ResolveException,
1221 call next resolver
1222
1223 @types: method, *args -> None
1224 method - method wich will be call for each resolver
1225 *args - arguments for the method
1226 '''
1227
1228 for resolver in self.__resolvers:
1229 try:
1230 return resolver.resolveIpsByHostname(hostname)
1231 except ResolveException, re:
1232 logger.warn(str(re))
1233 raise self._IP_RESOLVE_EXCEPTION
1234
1235
1243
1244
1246 - def __init__(self, shell, dnsServerAddress=None):
1247 '@types: Shell, str, str'
1248 self.__shell = shell
1249 self.__dnsResolver = DNSResolver(shell)
1250 ipResolver = IpResolver(dnsServerAddress, None)
1251 self.__ipResolver = ipResolver
1252
1253
1254
1255
1256 ipResolver.localShell = shell
1257 if hasattr(shell, 'execCmd'):
1258 shell.executeCmd = shell.execCmd
1259
1275
1277 '''@types: str -> list[str]
1278 @raise ResolveException: Failed to resolve IPs
1279 @note: When resolved IP is local (loopback) it will be replaced with
1280 destination IP address if such was specified
1281 while initializing this DNS resolver
1282 '''
1283 if not hostname:
1284 raise ValueError("Hostname is not specified")
1285 try:
1286 ip = self.__ipResolver.resolveHostIp(hostname)
1287 except Exception, ex:
1288 logger.debugException(str(ex))
1289 raise self._IP_RESOLVE_EXCEPTION
1290 if not ip:
1291 raise self._IP_RESOLVE_EXCEPTION
1292 return [ip]
1293
1294
1296 r''' Factory method to create DNS resolver
1297 @types: Shell -> BaseDnsResolver'''
1298 return DnsResolverByShell(shell, dnsServerAddress)
1299
1300
1302 'DNS Resolver that uses java API - InetAddress'
1303
1305 '''@types: str -> list[str]
1306 @raise ResolveException: Failed to resolve hostnames
1307 '''
1308 if not ip:
1309 raise ValueError("Ip is not specified")
1310 dnsName = None
1311 try:
1312 dnsName = str(InetAddress.getByName(ip).getHostName())
1313 except JException, je:
1314 logger.debug(str(je))
1315 raise self._HOSTNAME_RESOLVE_EXCEPTION
1316 if not dnsName or dnsName == ip:
1317 raise self._HOSTNAME_RESOLVE_EXCEPTION
1318 return [dnsName]
1319
1321 '''@types: str -> list[str]
1322 @raise ResolveException: Failed to resolve IPs
1323 @note: When resolved IP is local (loopback) it will be replaced
1324 with destination IP address if such was specified
1325 while initializing this DNS resolver
1326 '''
1327 if not hostname:
1328 raise ValueError("hostname is not specified")
1329 ip = None
1330 try:
1331 ip = str(InetAddress.getByName(hostname).getHostAddress())
1332 except JException, ex:
1333 logger.debug(str(ex))
1334 raise self._IP_RESOLVE_EXCEPTION
1335 if not ip:
1336 raise self._IP_RESOLVE_EXCEPTION
1337 return [ip]
1338
1339
1342 self.__ipProtocols = ipProtocols
1343
1345 '''@types: str -> int'''
1346 return self.__ipProtocols.getProtocolCode(protocol)
1347
1348 from com.hp.ucmdb.discovery.library.communication.downloader.cfgfiles import IPProtocols as JIPProtocols
1349
1350 IPPROTOCOLS = __IPProtocols(JIPProtocols)
1351
1352
1354 - def __init__(self, domainScopeManager):
1355 self.__domainScopeManager = domainScopeManager
1356
1357 - def isIpOutOfScope(self, ipAddress):
1358 '''@types: str -> bool '''
1359 return self.__domainScopeManager.isIpOutOfScope(ipAddress)
1360
1361 from com.hp.ucmdb.discovery.library.scope import DomainScopeManager as JDomainScopeManager
1362 DOMAIN_SCOPE_MANAGER = __DomainScopeManager(JDomainScopeManager)
1363