16ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti#!/usr/bin/python
2334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti#
3334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti# Copyright 2014 The Android Open Source Project
4334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti#
5334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti# Licensed under the Apache License, Version 2.0 (the "License");
6334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti# you may not use this file except in compliance with the License.
7334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti# You may obtain a copy of the License at
8334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti#
9334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti# http://www.apache.org/licenses/LICENSE-2.0
10334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti#
11334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti# Unless required by applicable law or agreed to in writing, software
12334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti# distributed under the License is distributed on an "AS IS" BASIS,
13334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti# See the License for the specific language governing permissions and
15334a05a24a5e4c27d9318967987fb181530deaffLorenzo Colitti# limitations under the License.
166ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
176ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittiimport fcntl
186ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittiimport os
198236c75d0492e37a2925fdcb2b3d3636a9c615dfLorenzo Colittiimport random
20d2344168138814630764df3da6b23dc839b4890dLorenzo Colittiimport re
21124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colittifrom socket import *  # pylint: disable=wildcard-import
226ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittiimport struct
236ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittiimport unittest
246ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
256ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittifrom scapy import all as scapy
266ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
276ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiSOL_IPV6 = 41
286ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIP_RECVERR = 11
296ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_RECVERR = 25
30a25ebd97dd121c7f89e59fa440b86ffc9822d012Lorenzo ColittiIP_TRANSPARENT = 19
31a25ebd97dd121c7f89e59fa440b86ffc9822d012Lorenzo ColittiIPV6_TRANSPARENT = 75
32a25ebd97dd121c7f89e59fa440b86ffc9822d012Lorenzo ColittiIPV6_TCLASS = 67
336ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_FLOWLABEL_MGR = 32
346ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_FLOWINFO_SEND = 33
356ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
36a213cb48c593f34544da80d0462572b2410e36b1Lorenzo ColittiSO_BINDTODEVICE = 25
37a213cb48c593f34544da80d0462572b2410e36b1Lorenzo ColittiSO_MARK = 36
38a213cb48c593f34544da80d0462572b2410e36b1Lorenzo ColittiSO_PROTOCOL = 38
39a213cb48c593f34544da80d0462572b2410e36b1Lorenzo ColittiSO_DOMAIN = 39
40a213cb48c593f34544da80d0462572b2410e36b1Lorenzo Colitti
4171f0b6211d9550ae267af2603a61789aa680cd28Lorenzo ColittiETH_P_IP = 0x0800
426ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiETH_P_IPV6 = 0x86dd
436ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
44610743878821c018ac1918b280ecfa097b77d6f0Lorenzo ColittiIPPROTO_GRE = 47
45610743878821c018ac1918b280ecfa097b77d6f0Lorenzo Colitti
466ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiSIOCSIFHWADDR = 0x8924
476ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
486ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_FL_A_GET = 0
496ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_FL_A_PUT = 1
506ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_FL_A_RENEW = 1
516ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
526ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_FL_F_CREATE = 1
536ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_FL_F_EXCL = 2
546ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
556ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_FL_S_NONE = 0
566ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_FL_S_EXCL = 1
576ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_FL_S_ANY = 255
586ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
59da3aa4c1e092b6cddc2e3b64ddde24777fedd931Lorenzo ColittiIFNAMSIZ = 16
60da3aa4c1e092b6cddc2e3b64ddde24777fedd931Lorenzo Colitti
616ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV4_PING = "\x08\x00\x00\x00\x0a\xce\x00\x03"
626ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_PING = "\x80\x00\x00\x00\x0a\xce\x00\x03"
636ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
646ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV4_ADDR = "8.8.8.8"
656ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_ADDR = "2001:4860:4860::8888"
666ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
676ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo ColittiIPV6_SEQ_DGRAM_HEADER = ("  sl  "
68124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti                         "local_address                         "
69124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti                         "remote_address                        "
70124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti                         "st tx_queue rx_queue tr tm->when retrnsmt"
71124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti                         "   uid  timeout inode ref pointer drops\n")
726ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
738236c75d0492e37a2925fdcb2b3d3636a9c615dfLorenzo Colitti# Arbitrary packet payload.
748236c75d0492e37a2925fdcb2b3d3636a9c615dfLorenzo ColittiUDP_PAYLOAD = str(scapy.DNS(rd=1,
758236c75d0492e37a2925fdcb2b3d3636a9c615dfLorenzo Colitti                            id=random.randint(0, 65535),
768236c75d0492e37a2925fdcb2b3d3636a9c615dfLorenzo Colitti                            qd=scapy.DNSQR(qname="wWW.GoOGle.CoM",
778236c75d0492e37a2925fdcb2b3d3636a9c615dfLorenzo Colitti                                           qtype="AAAA")))
788236c75d0492e37a2925fdcb2b3d3636a9c615dfLorenzo Colitti
79610743878821c018ac1918b280ecfa097b77d6f0Lorenzo Colitti# Unix group to use if we want to open sockets as non-root.
80610743878821c018ac1918b280ecfa097b77d6f0Lorenzo ColittiAID_INET = 3003
8171f0b6211d9550ae267af2603a61789aa680cd28Lorenzo Colitti
826ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
83105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colittidef LinuxVersion():
84105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti  # Example: "3.4.67-00753-gb7a556f".
85105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti  # Get the part before the dash.
86105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti  version = os.uname()[2].split("-")[0]
87105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti  # Convert it into a tuple such as (3, 4, 67). That allows comparing versions
88105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti  # using < and >, since tuples are compared lexicographically.
89105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti  version = tuple(int(i) for i in version.split("."))
90105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti  return version
91105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti
92105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti
93105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo ColittiLINUX_VERSION = LinuxVersion()
94105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti
95105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti
966ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef SetSocketTimeout(sock, ms):
976ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  s = ms / 1000
986ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  us = (ms % 1000) * 1000
996ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  sock.setsockopt(SOL_SOCKET, SO_RCVTIMEO, struct.pack("LL", s, us))
1006ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
101124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
102a25ebd97dd121c7f89e59fa440b86ffc9822d012Lorenzo Colittidef SetSocketTos(s, tos):
103a25ebd97dd121c7f89e59fa440b86ffc9822d012Lorenzo Colitti  level = {AF_INET: SOL_IP, AF_INET6: SOL_IPV6}[s.family]
104a25ebd97dd121c7f89e59fa440b86ffc9822d012Lorenzo Colitti  option = {AF_INET: IP_TOS, AF_INET6: IPV6_TCLASS}[s.family]
105a25ebd97dd121c7f89e59fa440b86ffc9822d012Lorenzo Colitti  s.setsockopt(level, option, tos)
106a25ebd97dd121c7f89e59fa440b86ffc9822d012Lorenzo Colitti
107124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
108717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colittidef SetNonBlocking(fd):
109717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0)
110717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
111717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti
112124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
113717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti# Convenience functions to create sockets.
1146ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef Socket(family, sock_type, protocol):
1156ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  s = socket(family, sock_type, protocol)
1166ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  SetSocketTimeout(s, 1000)
1176ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  return s
1186ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
119124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
120717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colittidef PingSocket(family):
121717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  proto = {AF_INET: IPPROTO_ICMP, AF_INET6: IPPROTO_ICMPV6}[family]
122717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  return Socket(family, SOCK_DGRAM, proto)
123717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti
124124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
1256ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef IPv4PingSocket():
126717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  return PingSocket(AF_INET)
1276ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
128124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
1296ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef IPv6PingSocket():
130717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  return PingSocket(AF_INET6)
131717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti
132124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
133717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colittidef TCPSocket(family):
134717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  s = Socket(family, SOCK_STREAM, IPPROTO_TCP)
135717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  SetNonBlocking(s.fileno())
136717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  return s
1376ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
138124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
1396ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef IPv4TCPSocket():
140717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  return TCPSocket(AF_INET)
1416ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
142124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
1436ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef IPv6TCPSocket():
144717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  return TCPSocket(AF_INET6)
145717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti
146124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
147717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colittidef UDPSocket(family):
148717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  return Socket(family, SOCK_DGRAM, IPPROTO_UDP)
1496ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
150124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
15171f0b6211d9550ae267af2603a61789aa680cd28Lorenzo Colittidef RawGRESocket(family):
15271f0b6211d9550ae267af2603a61789aa680cd28Lorenzo Colitti  s = Socket(family, SOCK_RAW, IPPROTO_GRE)
1536ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  return s
1546ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
155124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
156f2dffc46c435e1260185eb525f237e862525c2beLorenzo Colittidef DisableLinger(sock):
157f2dffc46c435e1260185eb525f237e862525c2beLorenzo Colitti  sock.setsockopt(SOL_SOCKET, SO_LINGER, struct.pack("ii", 1, 0))
158f2dffc46c435e1260185eb525f237e862525c2beLorenzo Colitti
159f2dffc46c435e1260185eb525f237e862525c2beLorenzo Colitti
16068e30d38f69f0a94df886a57b334e836cc48050eLorenzo Colittidef CreateSocketPair(family, socktype, addr):
16168e30d38f69f0a94df886a57b334e836cc48050eLorenzo Colitti  clientsock = socket(family, socktype, 0)
16268e30d38f69f0a94df886a57b334e836cc48050eLorenzo Colitti  listensock = socket(family, socktype, 0)
16368e30d38f69f0a94df886a57b334e836cc48050eLorenzo Colitti  listensock.bind((addr, 0))
16468e30d38f69f0a94df886a57b334e836cc48050eLorenzo Colitti  addr = listensock.getsockname()
16568e30d38f69f0a94df886a57b334e836cc48050eLorenzo Colitti  listensock.listen(1)
16668e30d38f69f0a94df886a57b334e836cc48050eLorenzo Colitti  clientsock.connect(addr)
16768e30d38f69f0a94df886a57b334e836cc48050eLorenzo Colitti  acceptedsock, _ = listensock.accept()
168f2dffc46c435e1260185eb525f237e862525c2beLorenzo Colitti  DisableLinger(clientsock)
169f2dffc46c435e1260185eb525f237e862525c2beLorenzo Colitti  DisableLinger(acceptedsock)
170f2dffc46c435e1260185eb525f237e862525c2beLorenzo Colitti  listensock.close()
17168e30d38f69f0a94df886a57b334e836cc48050eLorenzo Colitti  return clientsock, acceptedsock
17268e30d38f69f0a94df886a57b334e836cc48050eLorenzo Colitti
17368e30d38f69f0a94df886a57b334e836cc48050eLorenzo Colitti
1746ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef GetInterfaceIndex(ifname):
1756ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  s = IPv4PingSocket()
176da3aa4c1e092b6cddc2e3b64ddde24777fedd931Lorenzo Colitti  ifr = struct.pack("%dsi" % IFNAMSIZ, ifname, 0)
1776ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  ifr = fcntl.ioctl(s, scapy.SIOCGIFINDEX, ifr)
178da3aa4c1e092b6cddc2e3b64ddde24777fedd931Lorenzo Colitti  return struct.unpack("%dsi" % IFNAMSIZ, ifr)[1]
1796ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
180124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
1816ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef SetInterfaceHWAddr(ifname, hwaddr):
182717357af1ea56f3474a17fb909efc0f86db31e15Lorenzo Colitti  s = IPv4PingSocket()
1836ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  hwaddr = hwaddr.replace(":", "")
1846ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  hwaddr = hwaddr.decode("hex")
1856ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  if len(hwaddr) != 6:
1866ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    raise ValueError("Unknown hardware address length %d" % len(hwaddr))
187da3aa4c1e092b6cddc2e3b64ddde24777fedd931Lorenzo Colitti  ifr = struct.pack("%dsH6s" % IFNAMSIZ, ifname, scapy.ARPHDR_ETHER, hwaddr)
188124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti  fcntl.ioctl(s, SIOCSIFHWADDR, ifr)
189124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
1906ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
1916ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef SetInterfaceState(ifname, up):
1926ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  s = IPv4PingSocket()
193da3aa4c1e092b6cddc2e3b64ddde24777fedd931Lorenzo Colitti  ifr = struct.pack("%dsH" % IFNAMSIZ, ifname, 0)
1946ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  ifr = fcntl.ioctl(s, scapy.SIOCGIFFLAGS, ifr)
195da3aa4c1e092b6cddc2e3b64ddde24777fedd931Lorenzo Colitti  _, flags = struct.unpack("%dsH" % IFNAMSIZ, ifr)
1966ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  if up:
1976ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    flags |= scapy.IFF_UP
1986ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  else:
1996ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    flags &= ~scapy.IFF_UP
200da3aa4c1e092b6cddc2e3b64ddde24777fedd931Lorenzo Colitti  ifr = struct.pack("%dsH" % IFNAMSIZ, ifname, flags)
2016ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  ifr = fcntl.ioctl(s, scapy.SIOCSIFFLAGS, ifr)
2026ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
203124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
2046ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef SetInterfaceUp(ifname):
2056ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  return SetInterfaceState(ifname, True)
2066ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
207124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
2086ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef SetInterfaceDown(ifname):
2096ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  return SetInterfaceState(ifname, False)
2106ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
211124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
2126ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef FormatProcAddress(unformatted):
2136ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  groups = []
2146ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  for i in xrange(0, len(unformatted), 4):
2156ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    groups.append(unformatted[i:i+4])
2166ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  formatted = ":".join(groups)
2176ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  # Compress the address.
2186ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  address = inet_ntop(AF_INET6, inet_pton(AF_INET6, formatted))
2196ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  return address
2206ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
2216ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
2226ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef FormatSockStatAddress(address):
2236ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  if ":" in address:
2246ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    family = AF_INET6
2256ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  else:
2266ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    family = AF_INET
2276ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  binary = inet_pton(family, address)
2286ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  out = ""
2296ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  for i in xrange(0, len(binary), 4):
2306ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    out += "%08X" % struct.unpack("=L", binary[i:i+4])
2316ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  return out
2326ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
2336ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
2346ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef GetLinkAddress(ifname, linklocal):
2356ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  addresses = open("/proc/net/if_inet6").readlines()
2366ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  for address in addresses:
237124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti    address = [s for s in address.strip().split(" ") if s]
2386ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    if address[5] == ifname:
2396ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti      if (linklocal and address[0].startswith("fe80")
2406ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti          or not linklocal and not address[0].startswith("fe80")):
2416ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti        # Convert the address from raw hex to something with colons in it.
2426ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti        return FormatProcAddress(address[0])
2436ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  return None
2446ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
245124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
2466ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef GetDefaultRoute(version=6):
2476ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  if version == 6:
2486ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    routes = open("/proc/net/ipv6_route").readlines()
2496ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    for route in routes:
250124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti      route = [s for s in route.strip().split(" ") if s]
2516ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti      if (route[0] == "00000000000000000000000000000000" and route[1] == "00"
2526ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti          # Routes in non-default tables end up in /proc/net/ipv6_route!!!
2536ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti          and route[9] != "lo" and not route[9].startswith("nettest")):
2546ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti        return FormatProcAddress(route[4]), route[9]
2556ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    raise ValueError("No IPv6 default route found")
2566ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  elif version == 4:
2576ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    routes = open("/proc/net/route").readlines()
2586ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    for route in routes:
259124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti      route = [s for s in route.strip().split("\t") if s]
260124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti      if route[1] == "00000000" and route[7] == "00000000":
2616ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti        gw, iface = route[2], route[0]
2626ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti        gw = inet_ntop(AF_INET, gw.decode("hex")[::-1])
2636ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti        return gw, iface
2646ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    raise ValueError("No IPv4 default route found")
2656ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  else:
2666ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    raise ValueError("Don't know about IPv%s" % version)
2676ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
268124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti
2696ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef GetDefaultRouteInterface():
2709c53e8a60125235f0c2263a06ba9a9d2b5419f2cLorenzo Colitti  unused_gw, iface = GetDefaultRoute()
2716ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  return iface
2726ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
2736ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
2746ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittidef MakeFlowLabelOption(addr, label):
2756ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  # struct in6_flowlabel_req {
2766ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  #         struct in6_addr flr_dst;
2776ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  #         __be32  flr_label;
2786ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  #         __u8    flr_action;
2796ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  #         __u8    flr_share;
2806ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  #         __u16   flr_flags;
2816ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  #         __u16   flr_expires;
2826ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  #         __u16   flr_linger;
2836ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  #         __u32   __flr_pad;
2846ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  #         /* Options in format of IPV6_PKTOPTIONS */
2856ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  # };
286124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti  fmt = "16sIBBHHH4s"
2876ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  assert struct.calcsize(fmt) == 32
2886ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  addr = inet_pton(AF_INET6, addr)
2896ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  assert len(addr) == 16
2906ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  label = htonl(label & 0xfffff)
2916ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  action = IPV6_FL_A_GET
2926ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  share = IPV6_FL_S_ANY
2936ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  flags = IPV6_FL_F_CREATE
294124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti  pad = "\x00" * 4
2956ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  return struct.pack(fmt, addr, label, action, share, flags, 0, 0, pad)
2966ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
2976ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
298124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colittidef SetFlowLabel(s, addr, label):
299124b5aae8ca65731b363d898e2da7a543e4b0e3eLorenzo Colitti  opt = MakeFlowLabelOption(addr, label)
3006ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  s.setsockopt(SOL_IPV6, IPV6_FLOWLABEL_MGR, opt)
301ac57df5a25e37f9fe2c6ec62d4d6a25f8b39c7ceLorenzo Colitti  # Caller also needs to do s.setsockopt(SOL_IPV6, IPV6_FLOWINFO_SEND, 1).
3026ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
3036ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
304cbcbda6d3d8b0c208590cd769bdcf044396ee68aLorenzo Colitti# Determine network configuration.
305cbcbda6d3d8b0c208590cd769bdcf044396ee68aLorenzo Colittitry:
306cbcbda6d3d8b0c208590cd769bdcf044396ee68aLorenzo Colitti  GetDefaultRoute(version=4)
307cbcbda6d3d8b0c208590cd769bdcf044396ee68aLorenzo Colitti  HAVE_IPV4 = True
308cbcbda6d3d8b0c208590cd769bdcf044396ee68aLorenzo Colittiexcept ValueError:
309cbcbda6d3d8b0c208590cd769bdcf044396ee68aLorenzo Colitti  HAVE_IPV4 = False
310cbcbda6d3d8b0c208590cd769bdcf044396ee68aLorenzo Colitti
3116ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittitry:
3126ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  GetDefaultRoute(version=6)
3136ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  HAVE_IPV6 = True
3146ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittiexcept ValueError:
3156ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  HAVE_IPV6 = False
3166ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
3176ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
318105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitticlass RunAsUid(object):
319105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti  """Context guard to run a code block as a given UID."""
320105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti
321105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti  def __init__(self, uid):
322105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti    self.uid = uid
323105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti
324105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti  def __enter__(self):
325105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti    if self.uid:
326105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti      self.saved_uid = os.geteuid()
327105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti      self.saved_groups = os.getgroups()
328105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti      if self.uid:
329105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti        os.setgroups(self.saved_groups + [AID_INET])
330105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti        os.seteuid(self.uid)
331105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti
332105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti  def __exit__(self, unused_type, unused_value, unused_traceback):
333105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti    if self.uid:
334105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti      os.seteuid(self.saved_uid)
335105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti      os.setgroups(self.saved_groups)
336105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti
337105bda9ccf001b11ca15ea48863df44ace2f5ba4Lorenzo Colitti
3386ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitticlass NetworkTest(unittest.TestCase):
3396ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
3406ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  def assertRaisesErrno(self, err_num, f, *args):
3416ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    msg = os.strerror(err_num)
3426ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti    self.assertRaisesRegexp(EnvironmentError, msg, f, *args)
3436ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
344d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti  def ReadProcNetSocket(self, protocol):
345d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    # Read file.
346d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    filename = "/proc/net/%s" % protocol
347d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    lines = open(filename).readlines()
348d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti
349d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    # Possibly check, and strip, header.
350d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    if protocol in ["icmp6", "raw6", "udp6"]:
351d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti      self.assertEqual(IPV6_SEQ_DGRAM_HEADER, lines[0])
352d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    lines = lines[1:]
353d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti
354d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    # Check contents.
355d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    if protocol.endswith("6"):
356d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti      addrlen = 32
357d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    else:
358d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti      addrlen = 8
359d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti
360d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    if protocol.startswith("tcp"):
361d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti      # Real sockets have 5 extra numbers, timewait sockets have none.
362d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti      end_regexp = "(| +[0-9]+ [0-9]+ [0-9]+ [0-9]+ -?[0-9]+|)$"
363d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    elif re.match("icmp|udp|raw", protocol):
364d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti      # Drops.
365d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti      end_regexp = " +([0-9]+) *$"
366d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    else:
367d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti      raise ValueError("Don't know how to parse %s" % filename)
368d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti
369d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    regexp = re.compile(r" *(\d+): "                    # bucket
370d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "([0-9A-F]{%d}:[0-9A-F]{4}) "   # srcaddr, port
371d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "([0-9A-F]{%d}:[0-9A-F]{4}) "   # dstaddr, port
372d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "([0-9A-F][0-9A-F]) "           # state
373d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "([0-9A-F]{8}:[0-9A-F]{8}) "    # mem
374d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "([0-9A-F]{2}:[0-9A-F]{8}) "    # ?
375d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "([0-9A-F]{8}) +"               # ?
376d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "([0-9]+) +"                    # uid
377d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "([0-9]+) +"                    # timeout
378d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "([0-9]+) +"                    # inode
379d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "([0-9]+) +"                    # refcnt
380d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "([0-9a-f]+)"                   # sp
381d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        "%s"                            # icmp has spaces
382d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti                        % (addrlen, addrlen, end_regexp))
383d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    # Return a list of lists with only source / dest addresses for now.
384d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    # TODO: consider returning a dict or namedtuple instead.
385d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    out = []
386d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    for line in lines:
387d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti      (_, src, dst, state, mem,
388d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti       _, _, uid, _, _, refcnt, _, extra) = regexp.match(line).groups()
389d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti      out.append([src, dst, state, mem, uid, refcnt, extra])
390d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti    return out
391d2344168138814630764df3da6b23dc839b4890dLorenzo Colitti
3926ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti
3936ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colittiif __name__ == "__main__":
3946ef3e4fdfd823b08aca5ea2c2368e956b5e0eaeaLorenzo Colitti  unittest.main()
395