-
Notifications
You must be signed in to change notification settings - Fork 85
/
openTun.py
166 lines (133 loc) · 5.52 KB
/
openTun.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# Copyright (c) 2010-2013, Regents of the University of California.
# All rights reserved.
#
# Released under the BSD 3-Clause license as published at the link below.
# https://openwsn.atlassian.net/wiki/display/OW/License
import logging
log = logging.getLogger('openTun')
log.setLevel(logging.ERROR)
log.addHandler(logging.NullHandler())
import sys
import socket
import time
import openvisualizer.openvisualizer_utils as u
from openvisualizer.eventBus import eventBusClient
# IPv6 address for TUN interface
IPV6PREFIX = [0xbb,0xbb,0x00,0x00,0x00,0x00,0x00,0x00]
IPV6HOST = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01]
def create():
'''
Module-based Factory method to create instance based on operating system
'''
# Must import here rather than at top of module to avoid a circular
# reference to OpenTun class.
if sys.platform.startswith('win32'):
from openTunWindows import OpenTunWindows
return OpenTunWindows()
elif sys.platform.startswith('linux'):
from openTunLinux import OpenTunLinux
return OpenTunLinux()
elif sys.platform.startswith('darwin'):
from openTunMACOS import OpenTunMACOS
return OpenTunMACOS()
else:
raise NotImplementedError('Platform {0} not supported'.format(sys.platform))
class OpenTun(eventBusClient.eventBusClient):
'''
Class which interfaces between a TUN virtual interface and an EventBus.
This class is abstract, with concrete subclases based on operating system.
'''
def __init__(self):
# log
log.info("create instance")
# store params
# register to receive outgoing network packets
eventBusClient.eventBusClient.__init__(
self,
name = 'OpenTun',
registrations = [
{
'sender' : self.WILDCARD,
'signal' : 'getNetworkPrefix',
'callback' : self._getNetworkPrefix_notif,
},
{
'sender' : self.WILDCARD,
'signal' : 'getNetworkHost',
'callback' : self._getNetworkHost_notif,
},
{
'sender' : self.WILDCARD,
'signal' : 'v6ToInternet',
'callback' : self._v6ToInternet_notif
},
]
)
# local variables
self.tunIf = self._createTunIf()
if self.tunIf:
self.tunReadThread = self._createTunReadThread()
else:
self.tunReadThread = None
# TODO: retrieve network prefix from interface settings
# announce network prefix
self.dispatch(
signal = 'networkPrefix',
data = IPV6PREFIX
)
#======================== public ==========================================
def close(self):
if self.tunReadThread:
self.tunReadThread.close()
# Send a packet to openTun interface to break out of blocking read.
attempts = 0
while self.tunReadThread.isAlive() and attempts < 3:
attempts += 1
try:
log.info('Sending UDP packet to close openTun')
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
# Destination must route through the TUN host, but not be the host itself.
# OK if host does not really exist.
dst = IPV6PREFIX + IPV6HOST
dst[15] += 1
# Payload and destination port are arbitrary
sock.sendto('stop', (u.formatIPv6Addr(dst),18004))
# Give thread some time to exit
time.sleep(0.05)
except Exception as err:
log.error('Unable to send UDP to close tunReadThread: {0}'.join(err))
#======================== private =========================================
def _v6ToInternet_notif(self,sender,signal,data):
'''
Called when receiving data from the EventBus.
This function forwards the data to the the TUN interface.
Read from tun interface and forward to 6lowPAN
'''
raise NotImplementedError('subclass must implement')
def _getNetworkPrefix_notif(self,sender,signal,data):
return IPV6PREFIX
def _getNetworkHost_notif(self,sender,signal,data):
return IPV6HOST
def _v6ToMesh_notif(self,data):
'''
Called when receiving data from the TUN interface.
This function forwards the data to the the EventBus.
Read from 6lowPAN and forward to tun interface
'''
# dispatch to EventBus
self.dispatch(
signal = 'v6ToMesh',
data = data,
)
def _createTunIf(self):
'''
Open a TUN/TAP interface and switch it to TUN mode.
:returns: The handler of the interface, which can be used for later
read/write operations.
'''
raise NotImplementedError('subclass must implement')
def _createTunReadThread(self):
'''
Creates the thread to read messages arriving from the TUN interface
'''
raise NotImplementedError('subclass must implement')