Statistics
| Branch: | Tag: | Revision:

root / nfdhcpd @ 07c8990f

History | View | Annotate | Download (41.5 kB)

1 1f3139f3 Apollon Oikonomopoulos
#!/usr/bin/env python
2 1f3139f3 Apollon Oikonomopoulos
#
3 1f3139f3 Apollon Oikonomopoulos
4 1f3139f3 Apollon Oikonomopoulos
# nfdcpd: A promiscuous, NFQUEUE-based DHCP server for virtual machine hosting
5 1f3139f3 Apollon Oikonomopoulos
# Copyright (c) 2010 GRNET SA
6 1f3139f3 Apollon Oikonomopoulos
#
7 1f3139f3 Apollon Oikonomopoulos
#    This program is free software; you can redistribute it and/or modify
8 1f3139f3 Apollon Oikonomopoulos
#    it under the terms of the GNU General Public License as published by
9 1f3139f3 Apollon Oikonomopoulos
#    the Free Software Foundation; either version 2 of the License, or
10 1f3139f3 Apollon Oikonomopoulos
#    (at your option) any later version.
11 1f3139f3 Apollon Oikonomopoulos
#
12 1f3139f3 Apollon Oikonomopoulos
#    This program is distributed in the hope that it will be useful,
13 1f3139f3 Apollon Oikonomopoulos
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1f3139f3 Apollon Oikonomopoulos
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 1f3139f3 Apollon Oikonomopoulos
#    GNU General Public License for more details.
16 1f3139f3 Apollon Oikonomopoulos
#
17 1f3139f3 Apollon Oikonomopoulos
#    You should have received a copy of the GNU General Public License along
18 1f3139f3 Apollon Oikonomopoulos
#    with this program; if not, write to the Free Software Foundation, Inc.,
19 1f3139f3 Apollon Oikonomopoulos
#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 1f3139f3 Apollon Oikonomopoulos
#
21 1f3139f3 Apollon Oikonomopoulos
22 1f3139f3 Apollon Oikonomopoulos
import os
23 40a561a7 Dimitris Aragiorgis
import signal
24 40a561a7 Dimitris Aragiorgis
import errno
25 1f3139f3 Apollon Oikonomopoulos
import re
26 6765a36f Apollon Oikonomopoulos
import sys
27 1f3139f3 Apollon Oikonomopoulos
import glob
28 fa04d422 Apollon Oikonomopoulos
import time
29 1f3139f3 Apollon Oikonomopoulos
import logging
30 1f3139f3 Apollon Oikonomopoulos
import logging.handlers
31 83027c6b Apollon Oikonomopoulos
import threading
32 feca7bb9 Apollon Oikonomopoulos
import traceback
33 1f3139f3 Apollon Oikonomopoulos
34 1f3139f3 Apollon Oikonomopoulos
import daemon
35 d9361b6e Dimitris Aragriorgs
import daemon.runner
36 df3e8fac Vangelis Koukis
import daemon.pidlockfile
37 1f3139f3 Apollon Oikonomopoulos
import nfqueue
38 1f3139f3 Apollon Oikonomopoulos
import pyinotify
39 856268f2 Vangelis Koukis
import setproctitle
40 883eb77e Dimitris Aragriorgs
from lockfile import LockTimeout
41 1f3139f3 Apollon Oikonomopoulos
42 1f3139f3 Apollon Oikonomopoulos
import IPy
43 810a20fa Apollon Oikonomopoulos
import socket
44 40a561a7 Dimitris Aragiorgis
import select
45 699cc6e3 Apollon Oikonomopoulos
from socket import AF_INET, AF_INET6
46 1f3139f3 Apollon Oikonomopoulos
47 68da8f20 Apollon Oikonomopoulos
from scapy.data import ETH_P_ALL
48 68da8f20 Apollon Oikonomopoulos
from scapy.packet import BasePacket
49 1f3139f3 Apollon Oikonomopoulos
from scapy.layers.l2 import Ether
50 1f3139f3 Apollon Oikonomopoulos
from scapy.layers.inet import IP, UDP
51 6765a36f Apollon Oikonomopoulos
from scapy.layers.inet6 import IPv6, ICMPv6ND_RA, ICMPv6ND_NA, \
52 6765a36f Apollon Oikonomopoulos
                               ICMPv6NDOptDstLLAddr, \
53 6765a36f Apollon Oikonomopoulos
                               ICMPv6NDOptPrefixInfo, \
54 6765a36f Apollon Oikonomopoulos
                               ICMPv6NDOptRDNSS
55 1f3139f3 Apollon Oikonomopoulos
from scapy.layers.dhcp import BOOTP, DHCP
56 06e6d9bc Dimitris Aragiorgis
from scapy.layers.dhcp6 import DHCP6_Reply, DHCP6OptDNSServers, \
57 06e6d9bc Dimitris Aragiorgis
                               DHCP6OptServerId, DHCP6OptClientId, \
58 7b0ebdd0 Dimitris Aragiorgis
                               DUID_LLT, DHCP6_InfoRequest, DHCP6OptDNSDomains
59 1f3139f3 Apollon Oikonomopoulos
60 856268f2 Vangelis Koukis
61 ea915b1a Apollon Oikonomopoulos
DEFAULT_CONFIG = "/etc/nfdhcpd/nfdhcpd.conf"
62 1f3139f3 Apollon Oikonomopoulos
DEFAULT_PATH = "/var/run/ganeti-dhcpd"
63 1f3139f3 Apollon Oikonomopoulos
DEFAULT_USER = "nobody"
64 ea915b1a Apollon Oikonomopoulos
DEFAULT_LEASE_LIFETIME = 604800 # 1 week
65 ea915b1a Apollon Oikonomopoulos
DEFAULT_LEASE_RENEWAL = 600  # 10 min
66 ea915b1a Apollon Oikonomopoulos
DEFAULT_RA_PERIOD = 300 # seconds
67 ea915b1a Apollon Oikonomopoulos
DHCP_DUMMY_SERVER_IP = "1.2.3.4"
68 1f3139f3 Apollon Oikonomopoulos
69 ea915b1a Apollon Oikonomopoulos
LOG_FILENAME = "nfdhcpd.log"
70 1f3139f3 Apollon Oikonomopoulos
71 1f3139f3 Apollon Oikonomopoulos
SYSFS_NET = "/sys/class/net"
72 1f3139f3 Apollon Oikonomopoulos
73 de311515 Dimitris Aragiorgis
LOG_FORMAT = "%(asctime)-15s %(levelname)-8s %(message)s"
74 1f3139f3 Apollon Oikonomopoulos
75 651e531d Apollon Oikonomopoulos
# Configuration file specification (see configobj documentation)
76 651e531d Apollon Oikonomopoulos
CONFIG_SPEC = """
77 651e531d Apollon Oikonomopoulos
[general]
78 651e531d Apollon Oikonomopoulos
pidfile = string()
79 651e531d Apollon Oikonomopoulos
datapath = string()
80 651e531d Apollon Oikonomopoulos
logdir = string()
81 651e531d Apollon Oikonomopoulos
user = string()
82 651e531d Apollon Oikonomopoulos
83 651e531d Apollon Oikonomopoulos
[dhcp]
84 651e531d Apollon Oikonomopoulos
enable_dhcp = boolean(default=True)
85 651e531d Apollon Oikonomopoulos
lease_lifetime = integer(min=0, max=4294967295)
86 651e531d Apollon Oikonomopoulos
lease_renewal = integer(min=0, max=4294967295)
87 651e531d Apollon Oikonomopoulos
server_ip = ip_addr()
88 651e531d Apollon Oikonomopoulos
dhcp_queue = integer(min=0, max=65535)
89 651e531d Apollon Oikonomopoulos
nameservers = ip_addr_list(family=4)
90 7d38c21d Dimitris Aragiorgis
domain = string(default=None)
91 651e531d Apollon Oikonomopoulos
92 651e531d Apollon Oikonomopoulos
[ipv6]
93 651e531d Apollon Oikonomopoulos
enable_ipv6 = boolean(default=True)
94 651e531d Apollon Oikonomopoulos
ra_period = integer(min=1, max=4294967295)
95 651e531d Apollon Oikonomopoulos
rs_queue = integer(min=0, max=65535)
96 651e531d Apollon Oikonomopoulos
ns_queue = integer(min=0, max=65535)
97 06e6d9bc Dimitris Aragiorgis
dhcp_queue = integer(min=0, max=65535)
98 651e531d Apollon Oikonomopoulos
nameservers = ip_addr_list(family=6)
99 7b0ebdd0 Dimitris Aragiorgis
domains = force_list(default=None)
100 651e531d Apollon Oikonomopoulos
"""
101 651e531d Apollon Oikonomopoulos
102 651e531d Apollon Oikonomopoulos
103 1f3139f3 Apollon Oikonomopoulos
DHCPDISCOVER = 1
104 1f3139f3 Apollon Oikonomopoulos
DHCPOFFER = 2
105 1f3139f3 Apollon Oikonomopoulos
DHCPREQUEST = 3
106 1f3139f3 Apollon Oikonomopoulos
DHCPDECLINE = 4
107 1f3139f3 Apollon Oikonomopoulos
DHCPACK = 5
108 1f3139f3 Apollon Oikonomopoulos
DHCPNAK = 6
109 1f3139f3 Apollon Oikonomopoulos
DHCPRELEASE = 7
110 1f3139f3 Apollon Oikonomopoulos
DHCPINFORM = 8
111 1f3139f3 Apollon Oikonomopoulos
112 1f3139f3 Apollon Oikonomopoulos
DHCP_TYPES = {
113 1f3139f3 Apollon Oikonomopoulos
    DHCPDISCOVER: "DHCPDISCOVER",
114 1f3139f3 Apollon Oikonomopoulos
    DHCPOFFER: "DHCPOFFER",
115 1f3139f3 Apollon Oikonomopoulos
    DHCPREQUEST: "DHCPREQUEST",
116 1f3139f3 Apollon Oikonomopoulos
    DHCPDECLINE: "DHCPDECLINE",
117 1f3139f3 Apollon Oikonomopoulos
    DHCPACK: "DHCPACK",
118 1f3139f3 Apollon Oikonomopoulos
    DHCPNAK: "DHCPNAK",
119 1f3139f3 Apollon Oikonomopoulos
    DHCPRELEASE: "DHCPRELEASE",
120 1f3139f3 Apollon Oikonomopoulos
    DHCPINFORM: "DHCPINFORM",
121 1f3139f3 Apollon Oikonomopoulos
}
122 1f3139f3 Apollon Oikonomopoulos
123 1f3139f3 Apollon Oikonomopoulos
DHCP_REQRESP = {
124 1f3139f3 Apollon Oikonomopoulos
    DHCPDISCOVER: DHCPOFFER,
125 1f3139f3 Apollon Oikonomopoulos
    DHCPREQUEST: DHCPACK,
126 1f3139f3 Apollon Oikonomopoulos
    DHCPINFORM: DHCPACK,
127 1f3139f3 Apollon Oikonomopoulos
    }
128 1f3139f3 Apollon Oikonomopoulos
129 519ec23c Apollon Oikonomopoulos
130 f54e48af Dimitris Aragiorgis
def get_indev(payload):
131 f54e48af Dimitris Aragiorgis
    try:
132 f54e48af Dimitris Aragiorgis
        indev_ifindex = payload.get_physindev()
133 f54e48af Dimitris Aragiorgis
        if indev_ifindex:
134 b8b91462 Dimitris Aragiorgis
            logging.debug(" - Incoming packet from bridge with ifindex %s",
135 b8b91462 Dimitris Aragiorgis
                          indev_ifindex)
136 f54e48af Dimitris Aragiorgis
            return indev_ifindex
137 f54e48af Dimitris Aragiorgis
    except AttributeError:
138 f54e48af Dimitris Aragiorgis
        #TODO: return error value
139 0fbb25c0 Dimitris Aragiorgis
        logging.debug("No get_physindev() supported")
140 f54e48af Dimitris Aragiorgis
        return 0
141 f54e48af Dimitris Aragiorgis
142 f54e48af Dimitris Aragiorgis
    indev_ifindex = payload.get_indev()
143 b8b91462 Dimitris Aragiorgis
    logging.debug(" - Incoming packet from tap with ifindex %s", indev_ifindex)
144 f54e48af Dimitris Aragiorgis
145 f54e48af Dimitris Aragiorgis
    return indev_ifindex
146 f54e48af Dimitris Aragiorgis
147 764f829a Christos Stavrakakis
148 6765a36f Apollon Oikonomopoulos
def parse_binding_file(path):
149 6765a36f Apollon Oikonomopoulos
    """ Read a client configuration from a tap file
150 6765a36f Apollon Oikonomopoulos
151 6765a36f Apollon Oikonomopoulos
    """
152 764f829a Christos Stavrakakis
    logging.info("Parsing binding file %s", path)
153 6765a36f Apollon Oikonomopoulos
    try:
154 6765a36f Apollon Oikonomopoulos
        iffile = open(path, 'r')
155 6765a36f Apollon Oikonomopoulos
    except EnvironmentError, e:
156 0fbb25c0 Dimitris Aragiorgis
        logging.warn(" - Unable to open binding file %s: %s", path, str(e))
157 a2eba3d0 Apollon Oikonomopoulos
        return None
158 6765a36f Apollon Oikonomopoulos
159 de1a1bb2 Dimitris Aragiorgis
    tap = os.path.basename(path)
160 de1a1bb2 Dimitris Aragiorgis
    indev = None
161 6765a36f Apollon Oikonomopoulos
    mac = None
162 de1a1bb2 Dimitris Aragiorgis
    ip = None
163 6765a36f Apollon Oikonomopoulos
    hostname = None
164 de1a1bb2 Dimitris Aragiorgis
    subnet = None
165 de1a1bb2 Dimitris Aragiorgis
    gateway = None
166 de1a1bb2 Dimitris Aragiorgis
    subnet6 = None
167 de1a1bb2 Dimitris Aragiorgis
    gateway6 = None
168 de1a1bb2 Dimitris Aragiorgis
    eui64 = None
169 de1a1bb2 Dimitris Aragiorgis
170 de1a1bb2 Dimitris Aragiorgis
    def get_value(line):
171 de1a1bb2 Dimitris Aragiorgis
        v = line.strip().split('=')[1]
172 de1a1bb2 Dimitris Aragiorgis
        if v == '':
173 764f829a Christos Stavrakakis
            return None
174 de1a1bb2 Dimitris Aragiorgis
        return v
175 6765a36f Apollon Oikonomopoulos
176 6765a36f Apollon Oikonomopoulos
    for line in iffile:
177 6765a36f Apollon Oikonomopoulos
        if line.startswith("IP="):
178 de1a1bb2 Dimitris Aragiorgis
            ip = get_value(line)
179 6765a36f Apollon Oikonomopoulos
        elif line.startswith("MAC="):
180 de1a1bb2 Dimitris Aragiorgis
            mac = get_value(line)
181 6765a36f Apollon Oikonomopoulos
        elif line.startswith("HOSTNAME="):
182 de1a1bb2 Dimitris Aragiorgis
            hostname = get_value(line)
183 de1a1bb2 Dimitris Aragiorgis
        elif line.startswith("INDEV="):
184 de1a1bb2 Dimitris Aragiorgis
            indev = get_value(line)
185 de1a1bb2 Dimitris Aragiorgis
        elif line.startswith("SUBNET="):
186 de1a1bb2 Dimitris Aragiorgis
            subnet = get_value(line)
187 de1a1bb2 Dimitris Aragiorgis
        elif line.startswith("GATEWAY="):
188 de1a1bb2 Dimitris Aragiorgis
            gateway = get_value(line)
189 de1a1bb2 Dimitris Aragiorgis
        elif line.startswith("SUBNET6="):
190 de1a1bb2 Dimitris Aragiorgis
            subnet6 = get_value(line)
191 de1a1bb2 Dimitris Aragiorgis
        elif line.startswith("GATEWAY6="):
192 de1a1bb2 Dimitris Aragiorgis
            gateway6 = get_value(line)
193 de1a1bb2 Dimitris Aragiorgis
        elif line.startswith("EUI64="):
194 de1a1bb2 Dimitris Aragiorgis
            eui64 = get_value(line)
195 de1a1bb2 Dimitris Aragiorgis
196 b526f9ae Stratos Psomadakis
    try:
197 8d3dcc3b Dimitris Aragiorgis
        return Client(tap=tap, mac=mac, ip=ip, hostname=hostname,
198 8d3dcc3b Dimitris Aragiorgis
                      indev=indev, subnet=subnet, gateway=gateway,
199 8d3dcc3b Dimitris Aragiorgis
                      subnet6=subnet6, gateway6=gateway6, eui64=eui64 )
200 8d3dcc3b Dimitris Aragiorgis
    except ValueError:
201 0fbb25c0 Dimitris Aragiorgis
        logging.warning(" - Cannot add client for host %s and IP %s on tap %s",
202 8d3dcc3b Dimitris Aragiorgis
                        hostname, ip, tap)
203 b526f9ae Stratos Psomadakis
        return None
204 6765a36f Apollon Oikonomopoulos
205 764f829a Christos Stavrakakis
206 699cc6e3 Apollon Oikonomopoulos
class ClientFileHandler(pyinotify.ProcessEvent):
207 699cc6e3 Apollon Oikonomopoulos
    def __init__(self, server):
208 1f3139f3 Apollon Oikonomopoulos
        pyinotify.ProcessEvent.__init__(self)
209 699cc6e3 Apollon Oikonomopoulos
        self.server = server
210 1f3139f3 Apollon Oikonomopoulos
211 764f829a Christos Stavrakakis
    def process_IN_DELETE(self, event):  # pylint: disable=C0103
212 6765a36f Apollon Oikonomopoulos
        """ Delete file handler
213 6765a36f Apollon Oikonomopoulos
214 6765a36f Apollon Oikonomopoulos
        Currently this removes an interface from the watch list
215 6765a36f Apollon Oikonomopoulos
216 6765a36f Apollon Oikonomopoulos
        """
217 de1a1bb2 Dimitris Aragiorgis
        self.server.remove_tap(event.name)
218 1f3139f3 Apollon Oikonomopoulos
219 764f829a Christos Stavrakakis
    def process_IN_CLOSE_WRITE(self, event):  # pylint: disable=C0103
220 6765a36f Apollon Oikonomopoulos
        """ Add file handler
221 6765a36f Apollon Oikonomopoulos
222 6765a36f Apollon Oikonomopoulos
        Currently this adds an interface to the watch list
223 6765a36f Apollon Oikonomopoulos
224 6765a36f Apollon Oikonomopoulos
        """
225 de1a1bb2 Dimitris Aragiorgis
        self.server.add_tap(os.path.join(event.path, event.name))
226 1f3139f3 Apollon Oikonomopoulos
227 699cc6e3 Apollon Oikonomopoulos
228 699cc6e3 Apollon Oikonomopoulos
class Client(object):
229 09f11926 Dimitris Aragiorgis
    def __init__(self, tap=None, indev=None,
230 09f11926 Dimitris Aragiorgis
                 mac=None, ip=None, hostname=None,
231 09f11926 Dimitris Aragiorgis
                 subnet=None, gateway=None,
232 09f11926 Dimitris Aragiorgis
                 subnet6=None, gateway6=None, eui64=None):
233 1f3139f3 Apollon Oikonomopoulos
        self.mac = mac
234 de1a1bb2 Dimitris Aragiorgis
        self.ip = ip
235 1f3139f3 Apollon Oikonomopoulos
        self.hostname = hostname
236 de1a1bb2 Dimitris Aragiorgis
        self.indev = indev
237 de1a1bb2 Dimitris Aragiorgis
        self.tap = tap
238 de1a1bb2 Dimitris Aragiorgis
        self.subnet = subnet
239 de1a1bb2 Dimitris Aragiorgis
        self.gateway = gateway
240 de1a1bb2 Dimitris Aragiorgis
        self.net = Subnet(net=subnet, gw=gateway, dev=tap)
241 de1a1bb2 Dimitris Aragiorgis
        self.subnet6 = subnet6
242 de1a1bb2 Dimitris Aragiorgis
        self.gateway6 = gateway6
243 de1a1bb2 Dimitris Aragiorgis
        self.net6 = Subnet(net=subnet6, gw=gateway6, dev=tap)
244 de1a1bb2 Dimitris Aragiorgis
        self.eui64 = eui64
245 fd7ca450 Dimitris Aragiorgis
        self.open_socket()
246 1f3139f3 Apollon Oikonomopoulos
247 1f3139f3 Apollon Oikonomopoulos
    def is_valid(self):
248 fac9f928 Dimitris Aragiorgis
        return self.mac is not None and self.hostname is not None
249 1f3139f3 Apollon Oikonomopoulos
250 1f3139f3 Apollon Oikonomopoulos
251 fd7ca450 Dimitris Aragiorgis
    def open_socket(self):
252 fd7ca450 Dimitris Aragiorgis
253 fd7ca450 Dimitris Aragiorgis
        logging.info(" - Opening L2 socket and binding to %s", self.tap)
254 fd7ca450 Dimitris Aragiorgis
        try:
255 fd7ca450 Dimitris Aragiorgis
            s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, ETH_P_ALL)
256 fd7ca450 Dimitris Aragiorgis
            s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0)
257 fd7ca450 Dimitris Aragiorgis
            s.bind((self.tap, ETH_P_ALL))
258 fd7ca450 Dimitris Aragiorgis
            self.socket = s
259 fd7ca450 Dimitris Aragiorgis
        except socket.error, e:
260 fd7ca450 Dimitris Aragiorgis
            logging.warning(" - Cannot open socket %s", e)
261 fd7ca450 Dimitris Aragiorgis
262 fd7ca450 Dimitris Aragiorgis
263 fd7ca450 Dimitris Aragiorgis
    def sendp(self, data):
264 fd7ca450 Dimitris Aragiorgis
265 fd7ca450 Dimitris Aragiorgis
        if isinstance(data, BasePacket):
266 fd7ca450 Dimitris Aragiorgis
            data = str(data)
267 fd7ca450 Dimitris Aragiorgis
268 fd7ca450 Dimitris Aragiorgis
        logging.debug(" - Sending raw packet %r", data)
269 fd7ca450 Dimitris Aragiorgis
270 fd7ca450 Dimitris Aragiorgis
        try:
271 fd7ca450 Dimitris Aragiorgis
            count = self.socket.send(data, socket.MSG_DONTWAIT)
272 fd7ca450 Dimitris Aragiorgis
        except socket.error, e:
273 fd7ca450 Dimitris Aragiorgis
            logging.warn(" - Send with MSG_DONTWAIT failed: %s", str(e))
274 fd7ca450 Dimitris Aragiorgis
            self.socket.close()
275 fd7ca450 Dimitris Aragiorgis
            self.open_socket()
276 fd7ca450 Dimitris Aragiorgis
            raise e
277 fd7ca450 Dimitris Aragiorgis
278 fd7ca450 Dimitris Aragiorgis
        ldata = len(data)
279 fd7ca450 Dimitris Aragiorgis
        logging.debug(" - Sent %d bytes on %s", count, self.tap)
280 fd7ca450 Dimitris Aragiorgis
        if count != ldata:
281 fd7ca450 Dimitris Aragiorgis
            logging.warn(" - Truncated msg: %d/%d bytes sent",
282 fd7ca450 Dimitris Aragiorgis
                         count, ldata)
283 fd7ca450 Dimitris Aragiorgis
284 fd7ca450 Dimitris Aragiorgis
285 1f3139f3 Apollon Oikonomopoulos
class Subnet(object):
286 1f3139f3 Apollon Oikonomopoulos
    def __init__(self, net=None, gw=None, dev=None):
287 1f3139f3 Apollon Oikonomopoulos
        if isinstance(net, str):
288 b526f9ae Stratos Psomadakis
            try:
289 b526f9ae Stratos Psomadakis
                self.net = IPy.IP(net)
290 8d3dcc3b Dimitris Aragiorgis
            except ValueError, e:
291 0fbb25c0 Dimitris Aragiorgis
                logging.warning(" - IPy error: %s", e)
292 8d3dcc3b Dimitris Aragiorgis
                raise e
293 1f3139f3 Apollon Oikonomopoulos
        else:
294 1f3139f3 Apollon Oikonomopoulos
            self.net = net
295 1f3139f3 Apollon Oikonomopoulos
        self.gw = gw
296 1f3139f3 Apollon Oikonomopoulos
        self.dev = dev
297 1f3139f3 Apollon Oikonomopoulos
298 1f3139f3 Apollon Oikonomopoulos
    @property
299 1f3139f3 Apollon Oikonomopoulos
    def netmask(self):
300 6765a36f Apollon Oikonomopoulos
        """ Return the netmask in textual representation
301 6765a36f Apollon Oikonomopoulos
302 6765a36f Apollon Oikonomopoulos
        """
303 1f3139f3 Apollon Oikonomopoulos
        return str(self.net.netmask())
304 1f3139f3 Apollon Oikonomopoulos
305 1f3139f3 Apollon Oikonomopoulos
    @property
306 1f3139f3 Apollon Oikonomopoulos
    def broadcast(self):
307 6765a36f Apollon Oikonomopoulos
        """ Return the broadcast address in textual representation
308 6765a36f Apollon Oikonomopoulos
309 6765a36f Apollon Oikonomopoulos
        """
310 1f3139f3 Apollon Oikonomopoulos
        return str(self.net.broadcast())
311 1f3139f3 Apollon Oikonomopoulos
312 247ad61d Apollon Oikonomopoulos
    @property
313 247ad61d Apollon Oikonomopoulos
    def prefix(self):
314 6765a36f Apollon Oikonomopoulos
        """ Return the network as an IPy.IP
315 6765a36f Apollon Oikonomopoulos
316 6765a36f Apollon Oikonomopoulos
        """
317 247ad61d Apollon Oikonomopoulos
        return self.net.net()
318 247ad61d Apollon Oikonomopoulos
319 247ad61d Apollon Oikonomopoulos
    @property
320 247ad61d Apollon Oikonomopoulos
    def prefixlen(self):
321 6765a36f Apollon Oikonomopoulos
        """ Return the prefix length as an integer
322 6765a36f Apollon Oikonomopoulos
323 6765a36f Apollon Oikonomopoulos
        """
324 247ad61d Apollon Oikonomopoulos
        return self.net.prefixlen()
325 247ad61d Apollon Oikonomopoulos
326 247ad61d Apollon Oikonomopoulos
    @staticmethod
327 247ad61d Apollon Oikonomopoulos
    def _make_eui64(net, mac):
328 247ad61d Apollon Oikonomopoulos
        """ Compute an EUI-64 address from an EUI-48 (MAC) address
329 247ad61d Apollon Oikonomopoulos
330 247ad61d Apollon Oikonomopoulos
        """
331 4a3ed624 Dimitris Aragiorgis
        if mac is None:
332 4a3ed624 Dimitris Aragiorgis
            return None
333 247ad61d Apollon Oikonomopoulos
        comp = mac.split(":")
334 247ad61d Apollon Oikonomopoulos
        prefix = IPy.IP(net).net().strFullsize().split(":")[:4]
335 247ad61d Apollon Oikonomopoulos
        eui64 = comp[:3] + ["ff", "fe"] + comp[3:]
336 247ad61d Apollon Oikonomopoulos
        eui64[0] = "%02x" % (int(eui64[0], 16) ^ 0x02)
337 247ad61d Apollon Oikonomopoulos
        for l in range(0, len(eui64), 2):
338 247ad61d Apollon Oikonomopoulos
            prefix += ["".join(eui64[l:l+2])]
339 247ad61d Apollon Oikonomopoulos
        return IPy.IP(":".join(prefix))
340 247ad61d Apollon Oikonomopoulos
341 247ad61d Apollon Oikonomopoulos
    def make_eui64(self, mac):
342 6765a36f Apollon Oikonomopoulos
        """ Compute an EUI-64 address from an EUI-48 (MAC) address in this
343 6765a36f Apollon Oikonomopoulos
        subnet.
344 6765a36f Apollon Oikonomopoulos
345 6765a36f Apollon Oikonomopoulos
        """
346 247ad61d Apollon Oikonomopoulos
        return self._make_eui64(self.net, mac)
347 247ad61d Apollon Oikonomopoulos
348 247ad61d Apollon Oikonomopoulos
    def make_ll64(self, mac):
349 6765a36f Apollon Oikonomopoulos
        """ Compute an IPv6 Link-local address from an EUI-48 (MAC) address
350 6765a36f Apollon Oikonomopoulos
351 6765a36f Apollon Oikonomopoulos
        """
352 247ad61d Apollon Oikonomopoulos
        return self._make_eui64("fe80::", mac)
353 247ad61d Apollon Oikonomopoulos
354 1f3139f3 Apollon Oikonomopoulos
355 764f829a Christos Stavrakakis
class VMNetProxy(object):  # pylint: disable=R0902
356 764f829a Christos Stavrakakis
    def __init__(self, data_path, dhcp_queue_num=None,  # pylint: disable=R0913
357 06e6d9bc Dimitris Aragiorgis
                 rs_queue_num=None, ns_queue_num=None, dhcpv6_queue_num=None,
358 ea915b1a Apollon Oikonomopoulos
                 dhcp_lease_lifetime=DEFAULT_LEASE_LIFETIME,
359 ea915b1a Apollon Oikonomopoulos
                 dhcp_lease_renewal=DEFAULT_LEASE_RENEWAL,
360 7b0ebdd0 Dimitris Aragiorgis
                 dhcp_domain=None,
361 6765a36f Apollon Oikonomopoulos
                 dhcp_server_ip=DHCP_DUMMY_SERVER_IP, dhcp_nameservers=None,
362 7b0ebdd0 Dimitris Aragiorgis
                 ra_period=DEFAULT_RA_PERIOD, ipv6_nameservers=None,
363 7b0ebdd0 Dimitris Aragiorgis
                 dhcpv6_domains=None):
364 ea915b1a Apollon Oikonomopoulos
365 f54e48af Dimitris Aragiorgis
        try:
366 f54e48af Dimitris Aragiorgis
            getattr(nfqueue.payload, 'get_physindev')
367 f54e48af Dimitris Aragiorgis
            self.mac_indexed_clients = False
368 f54e48af Dimitris Aragiorgis
        except AttributeError:
369 f54e48af Dimitris Aragiorgis
            self.mac_indexed_clients = True
370 1f3139f3 Apollon Oikonomopoulos
        self.data_path = data_path
371 ea915b1a Apollon Oikonomopoulos
        self.lease_lifetime = dhcp_lease_lifetime
372 ea915b1a Apollon Oikonomopoulos
        self.lease_renewal = dhcp_lease_renewal
373 7d38c21d Dimitris Aragiorgis
        self.dhcp_domain = dhcp_domain
374 ea915b1a Apollon Oikonomopoulos
        self.dhcp_server_ip = dhcp_server_ip
375 ea915b1a Apollon Oikonomopoulos
        self.ra_period = ra_period
376 6765a36f Apollon Oikonomopoulos
        if dhcp_nameservers is None:
377 6765a36f Apollon Oikonomopoulos
            self.dhcp_nameserver = []
378 6765a36f Apollon Oikonomopoulos
        else:
379 6765a36f Apollon Oikonomopoulos
            self.dhcp_nameservers = dhcp_nameservers
380 6765a36f Apollon Oikonomopoulos
381 6765a36f Apollon Oikonomopoulos
        if ipv6_nameservers is None:
382 6765a36f Apollon Oikonomopoulos
            self.ipv6_nameservers = []
383 6765a36f Apollon Oikonomopoulos
        else:
384 6765a36f Apollon Oikonomopoulos
            self.ipv6_nameservers = ipv6_nameservers
385 6765a36f Apollon Oikonomopoulos
386 7b0ebdd0 Dimitris Aragiorgis
        if dhcpv6_domains is None:
387 7b0ebdd0 Dimitris Aragiorgis
            self.dhcpv6_domains = []
388 7b0ebdd0 Dimitris Aragiorgis
        else:
389 7b0ebdd0 Dimitris Aragiorgis
            self.dhcpv6_domains = dhcpv6_domains
390 7b0ebdd0 Dimitris Aragiorgis
391 31d21144 Apollon Oikonomopoulos
        self.ipv6_enabled = False
392 ea915b1a Apollon Oikonomopoulos
393 1f3139f3 Apollon Oikonomopoulos
        self.clients = {}
394 de1a1bb2 Dimitris Aragiorgis
        #self.subnets = {}
395 de1a1bb2 Dimitris Aragiorgis
        #self.ifaces = {}
396 de1a1bb2 Dimitris Aragiorgis
        #self.v6nets = {}
397 699cc6e3 Apollon Oikonomopoulos
        self.nfq = {}
398 699cc6e3 Apollon Oikonomopoulos
399 1f3139f3 Apollon Oikonomopoulos
        # Inotify setup
400 1f3139f3 Apollon Oikonomopoulos
        self.wm = pyinotify.WatchManager()
401 1f3139f3 Apollon Oikonomopoulos
        mask = pyinotify.EventsCodes.ALL_FLAGS["IN_DELETE"]
402 1f3139f3 Apollon Oikonomopoulos
        mask |= pyinotify.EventsCodes.ALL_FLAGS["IN_CLOSE_WRITE"]
403 6765a36f Apollon Oikonomopoulos
        inotify_handler = ClientFileHandler(self)
404 6765a36f Apollon Oikonomopoulos
        self.notifier = pyinotify.Notifier(self.wm, inotify_handler)
405 1f3139f3 Apollon Oikonomopoulos
        self.wm.add_watch(self.data_path, mask, rec=True)
406 1f3139f3 Apollon Oikonomopoulos
407 699cc6e3 Apollon Oikonomopoulos
        # NFQUEUE setup
408 699cc6e3 Apollon Oikonomopoulos
        if dhcp_queue_num is not None:
409 fd7ca450 Dimitris Aragiorgis
            self._setup_nfqueue(dhcp_queue_num, AF_INET, self.dhcp_response, 0)
410 699cc6e3 Apollon Oikonomopoulos
411 699cc6e3 Apollon Oikonomopoulos
        if rs_queue_num is not None:
412 3f442273 Dimitris Aragiorgis
            self._setup_nfqueue(rs_queue_num, AF_INET6, self.rs_response, 10)
413 31d21144 Apollon Oikonomopoulos
            self.ipv6_enabled = True
414 699cc6e3 Apollon Oikonomopoulos
415 699cc6e3 Apollon Oikonomopoulos
        if ns_queue_num is not None:
416 3f442273 Dimitris Aragiorgis
            self._setup_nfqueue(ns_queue_num, AF_INET6, self.ns_response, 10)
417 31d21144 Apollon Oikonomopoulos
            self.ipv6_enabled = True
418 699cc6e3 Apollon Oikonomopoulos
419 06e6d9bc Dimitris Aragiorgis
        if dhcpv6_queue_num is not None:
420 06e6d9bc Dimitris Aragiorgis
            self._setup_nfqueue(dhcpv6_queue_num, AF_INET6, self.dhcpv6_response, 10)
421 06e6d9bc Dimitris Aragiorgis
            self.ipv6_enabled = True
422 06e6d9bc Dimitris Aragiorgis
423 09f11926 Dimitris Aragiorgis
    def get_binding(self, ifindex, mac):
424 09f11926 Dimitris Aragiorgis
        try:
425 09f11926 Dimitris Aragiorgis
            if self.mac_indexed_clients:
426 09f11926 Dimitris Aragiorgis
                logging.debug(" - Getting binding for mac %s", mac)
427 09f11926 Dimitris Aragiorgis
                b = self.clients[mac]
428 09f11926 Dimitris Aragiorgis
            else:
429 09f11926 Dimitris Aragiorgis
                logging.debug(" - Getting binding for ifindex %s", ifindex)
430 09f11926 Dimitris Aragiorgis
                b = self.clients[ifindex]
431 09f11926 Dimitris Aragiorgis
            return b
432 09f11926 Dimitris Aragiorgis
        except KeyError:
433 09f11926 Dimitris Aragiorgis
            logging.debug(" - No client found for mac / ifindex %s / %s",
434 09f11926 Dimitris Aragiorgis
                          mac, ifindex)
435 09f11926 Dimitris Aragiorgis
            return None
436 8d3dcc3b Dimitris Aragiorgis
437 36e1175b Apollon Oikonomopoulos
    def _cleanup(self):
438 36e1175b Apollon Oikonomopoulos
        """ Free all resources for a graceful exit
439 36e1175b Apollon Oikonomopoulos
440 36e1175b Apollon Oikonomopoulos
        """
441 36e1175b Apollon Oikonomopoulos
        logging.info("Cleaning up")
442 36e1175b Apollon Oikonomopoulos
443 0fbb25c0 Dimitris Aragiorgis
        logging.debug(" - Closing netfilter queues")
444 09f11926 Dimitris Aragiorgis
        for q, _ in self.nfq.values():
445 36e1175b Apollon Oikonomopoulos
            q.close()
446 36e1175b Apollon Oikonomopoulos
447 0fbb25c0 Dimitris Aragiorgis
        logging.debug(" - Stopping inotify watches")
448 36e1175b Apollon Oikonomopoulos
        self.notifier.stop()
449 36e1175b Apollon Oikonomopoulos
450 0fbb25c0 Dimitris Aragiorgis
        logging.info(" - Cleanup finished")
451 36e1175b Apollon Oikonomopoulos
452 3f442273 Dimitris Aragiorgis
    def _setup_nfqueue(self, queue_num, family, callback, pending):
453 764f829a Christos Stavrakakis
        logging.info("Setting up NFQUEUE for queue %d, AF %s",
454 6765a36f Apollon Oikonomopoulos
                      queue_num, family)
455 699cc6e3 Apollon Oikonomopoulos
        q = nfqueue.queue()
456 699cc6e3 Apollon Oikonomopoulos
        q.set_callback(callback)
457 699cc6e3 Apollon Oikonomopoulos
        q.fast_open(queue_num, family)
458 ca7b6d21 Dimitris Aragiorgis
        q.set_queue_maxlen(5000)
459 1f3139f3 Apollon Oikonomopoulos
        # This is mandatory for the queue to operate
460 699cc6e3 Apollon Oikonomopoulos
        q.set_mode(nfqueue.NFQNL_COPY_PACKET)
461 3f442273 Dimitris Aragiorgis
        self.nfq[q.get_fd()] = (q, pending)
462 0fbb25c0 Dimitris Aragiorgis
        logging.debug(" - Successfully set up NFQUEUE %d", queue_num)
463 1f3139f3 Apollon Oikonomopoulos
464 1f3139f3 Apollon Oikonomopoulos
    def build_config(self):
465 1f3139f3 Apollon Oikonomopoulos
        self.clients.clear()
466 1f3139f3 Apollon Oikonomopoulos
467 6765a36f Apollon Oikonomopoulos
        for path in glob.glob(os.path.join(self.data_path, "*")):
468 de1a1bb2 Dimitris Aragiorgis
            self.add_tap(path)
469 1f3139f3 Apollon Oikonomopoulos
470 40a561a7 Dimitris Aragiorgis
        self.print_clients()
471 3596e9b6 Dimitris Aragiorgis
472 1f3139f3 Apollon Oikonomopoulos
    def get_ifindex(self, iface):
473 1f3139f3 Apollon Oikonomopoulos
        """ Get the interface index from sysfs
474 1f3139f3 Apollon Oikonomopoulos
475 1f3139f3 Apollon Oikonomopoulos
        """
476 0fbb25c0 Dimitris Aragiorgis
        logging.debug(" - Getting ifindex for interface %s from sysfs", iface)
477 764f829a Christos Stavrakakis
478 6765a36f Apollon Oikonomopoulos
        path = os.path.abspath(os.path.join(SYSFS_NET, iface, "ifindex"))
479 6765a36f Apollon Oikonomopoulos
        if not path.startswith(SYSFS_NET):
480 1f3139f3 Apollon Oikonomopoulos
            return None
481 1f3139f3 Apollon Oikonomopoulos
482 1f3139f3 Apollon Oikonomopoulos
        ifindex = None
483 1f3139f3 Apollon Oikonomopoulos
484 1f3139f3 Apollon Oikonomopoulos
        try:
485 6765a36f Apollon Oikonomopoulos
            f = open(path, 'r')
486 810a20fa Apollon Oikonomopoulos
        except EnvironmentError:
487 0fbb25c0 Dimitris Aragiorgis
            logging.debug(" - %s is probably down, removing", iface)
488 de1a1bb2 Dimitris Aragiorgis
            self.remove_tap(iface)
489 1f3139f3 Apollon Oikonomopoulos
490 810a20fa Apollon Oikonomopoulos
            return ifindex
491 810a20fa Apollon Oikonomopoulos
492 810a20fa Apollon Oikonomopoulos
        try:
493 810a20fa Apollon Oikonomopoulos
            ifindex = f.readline().strip()
494 810a20fa Apollon Oikonomopoulos
            try:
495 810a20fa Apollon Oikonomopoulos
                ifindex = int(ifindex)
496 810a20fa Apollon Oikonomopoulos
            except ValueError, e:
497 0fbb25c0 Dimitris Aragiorgis
                logging.warn(" - Failed to get ifindex for %s, cannot parse"
498 0fbb25c0 Dimitris Aragiorgis
                             " sysfs output '%s'", iface, ifindex)
499 810a20fa Apollon Oikonomopoulos
        except EnvironmentError, e:
500 0fbb25c0 Dimitris Aragiorgis
            logging.warn(" - Error reading %s's ifindex from sysfs: %s",
501 6765a36f Apollon Oikonomopoulos
                         iface, str(e))
502 de1a1bb2 Dimitris Aragiorgis
            self.remove_tap(iface)
503 810a20fa Apollon Oikonomopoulos
        finally:
504 810a20fa Apollon Oikonomopoulos
            f.close()
505 810a20fa Apollon Oikonomopoulos
506 1f3139f3 Apollon Oikonomopoulos
        return ifindex
507 699cc6e3 Apollon Oikonomopoulos
508 1f3139f3 Apollon Oikonomopoulos
    def get_iface_hw_addr(self, iface):
509 1f3139f3 Apollon Oikonomopoulos
        """ Get the interface hardware address from sysfs
510 1f3139f3 Apollon Oikonomopoulos
511 1f3139f3 Apollon Oikonomopoulos
        """
512 0fbb25c0 Dimitris Aragiorgis
        logging.debug(" - Getting mac for iface %s", iface)
513 6765a36f Apollon Oikonomopoulos
        path = os.path.abspath(os.path.join(SYSFS_NET, iface, "address"))
514 6765a36f Apollon Oikonomopoulos
        if not path.startswith(SYSFS_NET):
515 1f3139f3 Apollon Oikonomopoulos
            return None
516 1f3139f3 Apollon Oikonomopoulos
517 1f3139f3 Apollon Oikonomopoulos
        addr = None
518 1f3139f3 Apollon Oikonomopoulos
        try:
519 6765a36f Apollon Oikonomopoulos
            f = open(path, 'r')
520 810a20fa Apollon Oikonomopoulos
        except EnvironmentError:
521 0fbb25c0 Dimitris Aragiorgis
            logging.debug(" - %s is probably down, removing", iface)
522 de1a1bb2 Dimitris Aragiorgis
            self.remove_tap(iface)
523 810a20fa Apollon Oikonomopoulos
            return addr
524 810a20fa Apollon Oikonomopoulos
525 810a20fa Apollon Oikonomopoulos
        try:
526 1f3139f3 Apollon Oikonomopoulos
            addr = f.readline().strip()
527 810a20fa Apollon Oikonomopoulos
        except EnvironmentError, e:
528 0fbb25c0 Dimitris Aragiorgis
            logging.warn(" - Failed to read hw address for %s from sysfs: %s",
529 6765a36f Apollon Oikonomopoulos
                         iface, str(e))
530 810a20fa Apollon Oikonomopoulos
        finally:
531 1f3139f3 Apollon Oikonomopoulos
            f.close()
532 6ca53b5c Apollon Oikonomopoulos
533 1f3139f3 Apollon Oikonomopoulos
        return addr
534 1f3139f3 Apollon Oikonomopoulos
535 de1a1bb2 Dimitris Aragiorgis
    def add_tap(self, path):
536 1f3139f3 Apollon Oikonomopoulos
        """ Add an interface to monitor
537 1f3139f3 Apollon Oikonomopoulos
538 1f3139f3 Apollon Oikonomopoulos
        """
539 de1a1bb2 Dimitris Aragiorgis
        tap = os.path.basename(path)
540 1f3139f3 Apollon Oikonomopoulos
541 fd7ca450 Dimitris Aragiorgis
        logging.info("Updating configuration for %s", tap)
542 d2c81e80 Dimitris Aragiorgis
        b = parse_binding_file(path)
543 d2c81e80 Dimitris Aragiorgis
        if b is None:
544 a2eba3d0 Apollon Oikonomopoulos
            return
545 d2c81e80 Dimitris Aragiorgis
        ifindex = self.get_ifindex(b.tap)
546 1f3139f3 Apollon Oikonomopoulos
547 1f3139f3 Apollon Oikonomopoulos
        if ifindex is None:
548 0fbb25c0 Dimitris Aragiorgis
            logging.warn(" - Stale configuration for %s found", tap)
549 1f3139f3 Apollon Oikonomopoulos
        else:
550 d2c81e80 Dimitris Aragiorgis
            if b.is_valid():
551 f54e48af Dimitris Aragiorgis
                if self.mac_indexed_clients:
552 f54e48af Dimitris Aragiorgis
                    self.clients[b.mac] = b
553 f54e48af Dimitris Aragiorgis
                else:
554 f54e48af Dimitris Aragiorgis
                    self.clients[ifindex] = b
555 0fbb25c0 Dimitris Aragiorgis
                logging.debug(" - Added client:")
556 0fbb25c0 Dimitris Aragiorgis
                logging.debug(" + %5s: %10s %20s %7s %15s",
557 f54e48af Dimitris Aragiorgis
                               ifindex, b.hostname, b.mac, b.tap, b.ip)
558 1f3139f3 Apollon Oikonomopoulos
559 de1a1bb2 Dimitris Aragiorgis
    def remove_tap(self, tap):
560 1f3139f3 Apollon Oikonomopoulos
        """ Cleanup clients on a removed interface
561 1f3139f3 Apollon Oikonomopoulos
562 1f3139f3 Apollon Oikonomopoulos
        """
563 f54e48af Dimitris Aragiorgis
        try:
564 40a561a7 Dimitris Aragiorgis
            for k, cl in self.clients.items():
565 0a2aed6e Dimitris Aragiorgis
                if cl.tap == tap:
566 fd7ca450 Dimitris Aragiorgis
                    logging.info("Removing client %s and closing socket on %s",
567 fd7ca450 Dimitris Aragiorgis
                                 cl.hostname, cl.tap)
568 fd7ca450 Dimitris Aragiorgis
                    logging.debug(" - %10s | %10s %20s %10s %20s",
569 40a561a7 Dimitris Aragiorgis
                                  k, cl.hostname, cl.mac, cl.tap, cl.ip)
570 fd7ca450 Dimitris Aragiorgis
                    cl.socket.close()
571 40a561a7 Dimitris Aragiorgis
                    del self.clients[k]
572 f54e48af Dimitris Aragiorgis
        except:
573 f54e48af Dimitris Aragiorgis
            logging.debug("Client on %s disappeared!!!", tap)
574 1f3139f3 Apollon Oikonomopoulos
575 fd7ca450 Dimitris Aragiorgis
576 9aa2fbe7 Dimitris Aragiorgis
    def dhcp_response(self, arg1, arg2=None):  # pylint: disable=W0613,R0914
577 de1a1bb2 Dimitris Aragiorgis
        """ Generate a reply to bnetfilter-queue-deva BOOTP/DHCP request
578 1f3139f3 Apollon Oikonomopoulos
579 1f3139f3 Apollon Oikonomopoulos
        """
580 fd7ca450 Dimitris Aragiorgis
        logging.info(" * Processing pending DHCP request")
581 9aa2fbe7 Dimitris Aragiorgis
        # Workaround for supporting both squeezy's nfqueue-bindings-python
582 9aa2fbe7 Dimitris Aragiorgis
        # and wheezy's python-nfqueue because for some reason the function's
583 9aa2fbe7 Dimitris Aragiorgis
        # signature has changed and has broken compatibility
584 9aa2fbe7 Dimitris Aragiorgis
        # See bug http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=718894
585 9aa2fbe7 Dimitris Aragiorgis
        if arg2:
586 9aa2fbe7 Dimitris Aragiorgis
            payload = arg2
587 9aa2fbe7 Dimitris Aragiorgis
        else:
588 9aa2fbe7 Dimitris Aragiorgis
            payload = arg1
589 1f3139f3 Apollon Oikonomopoulos
        # Decode the response - NFQUEUE relays IP packets
590 1f3139f3 Apollon Oikonomopoulos
        pkt = IP(payload.get_data())
591 f54e48af Dimitris Aragiorgis
        #logging.debug(pkt.show())
592 699cc6e3 Apollon Oikonomopoulos
593 1f3139f3 Apollon Oikonomopoulos
        # Get the client MAC address
594 1f3139f3 Apollon Oikonomopoulos
        resp = pkt.getlayer(BOOTP).copy()
595 1f3139f3 Apollon Oikonomopoulos
        hlen = resp.hlen
596 1f3139f3 Apollon Oikonomopoulos
        mac = resp.chaddr[:hlen].encode("hex")
597 764f829a Christos Stavrakakis
        mac, _ = re.subn(r'([0-9a-fA-F]{2})', r'\1:', mac, hlen - 1)
598 1f3139f3 Apollon Oikonomopoulos
599 1f3139f3 Apollon Oikonomopoulos
        # Server responses are always BOOTREPLYs
600 1f3139f3 Apollon Oikonomopoulos
        resp.op = "BOOTREPLY"
601 1f3139f3 Apollon Oikonomopoulos
        del resp.payload
602 1f3139f3 Apollon Oikonomopoulos
603 f54e48af Dimitris Aragiorgis
        indev = get_indev(payload)
604 f54e48af Dimitris Aragiorgis
605 09f11926 Dimitris Aragiorgis
        binding = self.get_binding(indev, mac)
606 f54e48af Dimitris Aragiorgis
        if binding is None:
607 f54e48af Dimitris Aragiorgis
            # We don't know anything about this interface, so accept the packet
608 f54e48af Dimitris Aragiorgis
            # and return
609 0fbb25c0 Dimitris Aragiorgis
            logging.debug(" - Ignoring DHCP request on unknown iface %s", indev)
610 f54e48af Dimitris Aragiorgis
            # We don't know what to do with this packet, so let the kernel
611 f54e48af Dimitris Aragiorgis
            # handle it
612 de1a1bb2 Dimitris Aragiorgis
            payload.set_verdict(nfqueue.NF_ACCEPT)
613 1f3139f3 Apollon Oikonomopoulos
            return
614 1f3139f3 Apollon Oikonomopoulos
615 de1a1bb2 Dimitris Aragiorgis
        # Signal the kernel that it shouldn't further process the packet
616 de1a1bb2 Dimitris Aragiorgis
        payload.set_verdict(nfqueue.NF_DROP)
617 1f3139f3 Apollon Oikonomopoulos
618 f54e48af Dimitris Aragiorgis
        if mac != binding.mac:
619 09f11926 Dimitris Aragiorgis
            logging.warn(" - Recieved spoofed DHCP request: mac %s, indev %s",
620 09f11926 Dimitris Aragiorgis
                         mac, indev)
621 f54e48af Dimitris Aragiorgis
            return
622 f54e48af Dimitris Aragiorgis
623 fac9f928 Dimitris Aragiorgis
        if not binding.ip:
624 fac9f928 Dimitris Aragiorgis
            logging.info(" - No IP found in binding file.")
625 fac9f928 Dimitris Aragiorgis
            return
626 fac9f928 Dimitris Aragiorgis
627 09f11926 Dimitris Aragiorgis
        logging.info(" - Generating DHCP response:"
628 09f11926 Dimitris Aragiorgis
                     " host %s, mac %s, tap %s, indev %s",
629 09f11926 Dimitris Aragiorgis
                       binding.hostname, mac, binding.tap, indev)
630 0fbb25c0 Dimitris Aragiorgis
631 0fbb25c0 Dimitris Aragiorgis
632 de1a1bb2 Dimitris Aragiorgis
        resp = Ether(dst=mac, src=self.get_iface_hw_addr(binding.indev))/\
633 699cc6e3 Apollon Oikonomopoulos
               IP(src=DHCP_DUMMY_SERVER_IP, dst=binding.ip)/\
634 1f3139f3 Apollon Oikonomopoulos
               UDP(sport=pkt.dport, dport=pkt.sport)/resp
635 de1a1bb2 Dimitris Aragiorgis
        subnet = binding.net
636 1f3139f3 Apollon Oikonomopoulos
637 1f3139f3 Apollon Oikonomopoulos
        if not DHCP in pkt:
638 0fbb25c0 Dimitris Aragiorgis
            logging.warn(" - Invalid request from %s on %s, no DHCP"
639 de1a1bb2 Dimitris Aragiorgis
                         " payload found", binding.mac, binding.tap)
640 1f3139f3 Apollon Oikonomopoulos
            return
641 1f3139f3 Apollon Oikonomopoulos
642 1f3139f3 Apollon Oikonomopoulos
        dhcp_options = []
643 1f3139f3 Apollon Oikonomopoulos
        requested_addr = binding.ip
644 1f3139f3 Apollon Oikonomopoulos
        for opt in pkt[DHCP].options:
645 1f3139f3 Apollon Oikonomopoulos
            if type(opt) is tuple and opt[0] == "message-type":
646 1f3139f3 Apollon Oikonomopoulos
                req_type = opt[1]
647 1f3139f3 Apollon Oikonomopoulos
            if type(opt) is tuple and opt[0] == "requested_addr":
648 1f3139f3 Apollon Oikonomopoulos
                requested_addr = opt[1]
649 1f3139f3 Apollon Oikonomopoulos
650 0fbb25c0 Dimitris Aragiorgis
        logging.info(" - %s from %s on %s", DHCP_TYPES.get(req_type, "UNKNOWN"),
651 de1a1bb2 Dimitris Aragiorgis
                     binding.mac, binding.tap)
652 26ba9dba Costas Drogos
653 7d38c21d Dimitris Aragiorgis
        if self.dhcp_domain:
654 7d38c21d Dimitris Aragiorgis
            domainname = self.dhcp_domain
655 7d38c21d Dimitris Aragiorgis
        else:
656 7d38c21d Dimitris Aragiorgis
            domainname = binding.hostname.split('.', 1)[-1]
657 7d38c21d Dimitris Aragiorgis
658 1f3139f3 Apollon Oikonomopoulos
        if req_type == DHCPREQUEST and requested_addr != binding.ip:
659 1f3139f3 Apollon Oikonomopoulos
            resp_type = DHCPNAK
660 0fbb25c0 Dimitris Aragiorgis
            logging.info(" - Sending DHCPNAK to %s on %s: requested %s"
661 f54e48af Dimitris Aragiorgis
                         " instead of %s", binding.mac, binding.tap,
662 f54e48af Dimitris Aragiorgis
                         requested_addr, binding.ip)
663 1f3139f3 Apollon Oikonomopoulos
664 1f3139f3 Apollon Oikonomopoulos
        elif req_type in (DHCPDISCOVER, DHCPREQUEST):
665 1f3139f3 Apollon Oikonomopoulos
            resp_type = DHCP_REQRESP[req_type]
666 f54e48af Dimitris Aragiorgis
            resp.yiaddr = binding.ip
667 1f3139f3 Apollon Oikonomopoulos
            dhcp_options += [
668 1f3139f3 Apollon Oikonomopoulos
                 ("hostname", binding.hostname),
669 7d38c21d Dimitris Aragiorgis
                 ("domain", domainname),
670 1f3139f3 Apollon Oikonomopoulos
                 ("broadcast_address", str(subnet.broadcast)),
671 1f3139f3 Apollon Oikonomopoulos
                 ("subnet_mask", str(subnet.netmask)),
672 ea915b1a Apollon Oikonomopoulos
                 ("renewal_time", self.lease_renewal),
673 ea915b1a Apollon Oikonomopoulos
                 ("lease_time", self.lease_lifetime),
674 1f3139f3 Apollon Oikonomopoulos
            ]
675 de1a1bb2 Dimitris Aragiorgis
            if subnet.gw:
676 764f829a Christos Stavrakakis
                dhcp_options += [("router", subnet.gw)]
677 0be961fb Apollon Oikonomopoulos
            dhcp_options += [("name_server", x) for x in self.dhcp_nameservers]
678 1f3139f3 Apollon Oikonomopoulos
679 1f3139f3 Apollon Oikonomopoulos
        elif req_type == DHCPINFORM:
680 1f3139f3 Apollon Oikonomopoulos
            resp_type = DHCP_REQRESP[req_type]
681 1f3139f3 Apollon Oikonomopoulos
            dhcp_options += [
682 1f3139f3 Apollon Oikonomopoulos
                 ("hostname", binding.hostname),
683 7d38c21d Dimitris Aragiorgis
                 ("domain", domainname),
684 1f3139f3 Apollon Oikonomopoulos
            ]
685 0be961fb Apollon Oikonomopoulos
            dhcp_options += [("name_server", x) for x in self.dhcp_nameservers]
686 1f3139f3 Apollon Oikonomopoulos
687 1f3139f3 Apollon Oikonomopoulos
        elif req_type == DHCPRELEASE:
688 1f3139f3 Apollon Oikonomopoulos
            # Log and ignore
689 09f11926 Dimitris Aragiorgis
            logging.info(" - DHCPRELEASE from %s on %s",
690 09f11926 Dimitris Aragiorgis
                         binding.hostname, binding.tap)
691 1f3139f3 Apollon Oikonomopoulos
            return
692 1f3139f3 Apollon Oikonomopoulos
693 1f3139f3 Apollon Oikonomopoulos
        # Finally, always add the server identifier and end options
694 1f3139f3 Apollon Oikonomopoulos
        dhcp_options += [
695 1f3139f3 Apollon Oikonomopoulos
            ("message-type", resp_type),
696 699cc6e3 Apollon Oikonomopoulos
            ("server_id", DHCP_DUMMY_SERVER_IP),
697 1f3139f3 Apollon Oikonomopoulos
            "end"
698 1f3139f3 Apollon Oikonomopoulos
        ]
699 1f3139f3 Apollon Oikonomopoulos
        resp /= DHCP(options=dhcp_options)
700 1f3139f3 Apollon Oikonomopoulos
701 0fbb25c0 Dimitris Aragiorgis
        logging.info(" - %s to %s (%s) on %s", DHCP_TYPES[resp_type], mac,
702 de1a1bb2 Dimitris Aragiorgis
                     binding.ip, binding.tap)
703 3596e9b6 Dimitris Aragiorgis
        try:
704 09f11926 Dimitris Aragiorgis
            binding.sendp(resp)
705 3596e9b6 Dimitris Aragiorgis
        except socket.error, e:
706 fd7ca450 Dimitris Aragiorgis
            logging.warn(" - DHCP response on %s (%s) failed: %s",
707 fd7ca450 Dimitris Aragiorgis
                         binding.tap, binding.hostname, str(e))
708 3596e9b6 Dimitris Aragiorgis
        except Exception, e:
709 fd7ca450 Dimitris Aragiorgis
            logging.warn(" - Unkown error during DHCP response on %s (%s): %s",
710 fd7ca450 Dimitris Aragiorgis
                         binding.tap, binding.hostname, str(e))
711 1f3139f3 Apollon Oikonomopoulos
712 06e6d9bc Dimitris Aragiorgis
    def dhcpv6_response(self, arg1, arg2=None):  # pylint: disable=W0613
713 06e6d9bc Dimitris Aragiorgis
714 06e6d9bc Dimitris Aragiorgis
        logging.info(" * Processing pending DHCPv6 request")
715 06e6d9bc Dimitris Aragiorgis
        # Workaround for supporting both squeezy's nfqueue-bindings-python
716 06e6d9bc Dimitris Aragiorgis
        # and wheezy's python-nfqueue because for some reason the function's
717 06e6d9bc Dimitris Aragiorgis
        # signature has changed and has broken compatibility
718 06e6d9bc Dimitris Aragiorgis
        # See bug http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=718894
719 06e6d9bc Dimitris Aragiorgis
        if arg2:
720 06e6d9bc Dimitris Aragiorgis
            payload = arg2
721 06e6d9bc Dimitris Aragiorgis
        else:
722 06e6d9bc Dimitris Aragiorgis
            payload = arg1
723 06e6d9bc Dimitris Aragiorgis
        pkt = IPv6(payload.get_data())
724 06e6d9bc Dimitris Aragiorgis
        indev = get_indev(payload)
725 06e6d9bc Dimitris Aragiorgis
726 06e6d9bc Dimitris Aragiorgis
        #TODO: figure out how to find the src mac
727 06e6d9bc Dimitris Aragiorgis
        mac = None
728 06e6d9bc Dimitris Aragiorgis
        binding = self.get_binding(indev, mac)
729 06e6d9bc Dimitris Aragiorgis
        if binding is None:
730 06e6d9bc Dimitris Aragiorgis
            # We don't know anything about this interface, so accept the packet
731 06e6d9bc Dimitris Aragiorgis
            # and return
732 06e6d9bc Dimitris Aragiorgis
            logging.debug(" - Ignoring dhcpv6 request for mac %s", mac)
733 06e6d9bc Dimitris Aragiorgis
            # We don't know what to do with this packet, so let the kernel
734 06e6d9bc Dimitris Aragiorgis
            # handle it
735 06e6d9bc Dimitris Aragiorgis
            payload.set_verdict(nfqueue.NF_ACCEPT)
736 06e6d9bc Dimitris Aragiorgis
            return
737 06e6d9bc Dimitris Aragiorgis
738 06e6d9bc Dimitris Aragiorgis
        # Signal the kernel that it shouldn't further process the packet
739 06e6d9bc Dimitris Aragiorgis
        payload.set_verdict(nfqueue.NF_DROP)
740 06e6d9bc Dimitris Aragiorgis
741 06e6d9bc Dimitris Aragiorgis
        subnet = binding.net6
742 06e6d9bc Dimitris Aragiorgis
743 07c8990f Dimitris Aragiorgis
        if subnet.net is None:
744 07c8990f Dimitris Aragiorgis
            logging.debug(" - No IPv6 network assigned for tap %s", binding.tap)
745 07c8990f Dimitris Aragiorgis
            return
746 07c8990f Dimitris Aragiorgis
747 06e6d9bc Dimitris Aragiorgis
        indevmac = self.get_iface_hw_addr(binding.indev)
748 06e6d9bc Dimitris Aragiorgis
        ifll = subnet.make_ll64(indevmac)
749 06e6d9bc Dimitris Aragiorgis
        if ifll is None:
750 06e6d9bc Dimitris Aragiorgis
            return
751 06e6d9bc Dimitris Aragiorgis
752 06e6d9bc Dimitris Aragiorgis
        ofll = subnet.make_ll64(binding.mac)
753 06e6d9bc Dimitris Aragiorgis
        if ofll is None:
754 06e6d9bc Dimitris Aragiorgis
            return
755 06e6d9bc Dimitris Aragiorgis
756 06e6d9bc Dimitris Aragiorgis
        logging.info(" - Generating DHCPv6 response for host %s (mac %s) on tap %s",
757 06e6d9bc Dimitris Aragiorgis
                      binding.hostname, binding.mac, binding.tap)
758 06e6d9bc Dimitris Aragiorgis
759 7b0ebdd0 Dimitris Aragiorgis
        if self.dhcpv6_domains:
760 7b0ebdd0 Dimitris Aragiorgis
            domains = self.dhcpv6_domains
761 7b0ebdd0 Dimitris Aragiorgis
        else:
762 7b0ebdd0 Dimitris Aragiorgis
            domains = [binding.hostname.split('.', 1)[-1]]
763 7b0ebdd0 Dimitris Aragiorgis
764 7b0ebdd0 Dimitris Aragiorgis
        # We do this in order not to caclulate optlen ourselves
765 7b0ebdd0 Dimitris Aragiorgis
        dnsdomains = str(DHCP6OptDNSDomains(dnsdomains=domains))
766 7b0ebdd0 Dimitris Aragiorgis
        dnsservers = str(DHCP6OptDNSServers(dnsservers=self.ipv6_nameservers))
767 7b0ebdd0 Dimitris Aragiorgis
768 06e6d9bc Dimitris Aragiorgis
        resp = Ether(src=indevmac, dst=binding.mac)/\
769 06e6d9bc Dimitris Aragiorgis
               IPv6(tc=192, src=str(ifll), dst=str(ofll))/\
770 06e6d9bc Dimitris Aragiorgis
               UDP(sport=pkt.dport, dport=pkt.sport)/\
771 06e6d9bc Dimitris Aragiorgis
               DHCP6_Reply(trid=pkt[DHCP6_InfoRequest].trid)/\
772 06e6d9bc Dimitris Aragiorgis
               DHCP6OptClientId(duid=pkt[DHCP6OptClientId].duid)/\
773 06e6d9bc Dimitris Aragiorgis
               DHCP6OptServerId(duid=DUID_LLT(lladdr=indevmac, timeval=time.time()))/\
774 7b0ebdd0 Dimitris Aragiorgis
               DHCP6OptDNSDomains(dnsdomains)/\
775 7b0ebdd0 Dimitris Aragiorgis
               DHCP6OptDNSServers(dnsservers)
776 06e6d9bc Dimitris Aragiorgis
777 06e6d9bc Dimitris Aragiorgis
        try:
778 06e6d9bc Dimitris Aragiorgis
            binding.sendp(resp)
779 06e6d9bc Dimitris Aragiorgis
        except socket.error, e:
780 06e6d9bc Dimitris Aragiorgis
            logging.warn(" - DHCPv6 on %s (%s) failed: %s",
781 06e6d9bc Dimitris Aragiorgis
                         binding.tap, binding.hostname, str(e))
782 06e6d9bc Dimitris Aragiorgis
        except Exception, e:
783 06e6d9bc Dimitris Aragiorgis
            logging.warn(" - Unkown error during DHCPv6 on %s (%s): %s",
784 06e6d9bc Dimitris Aragiorgis
                         binding.tap, binding.hostname, str(e))
785 06e6d9bc Dimitris Aragiorgis
786 06e6d9bc Dimitris Aragiorgis
787 9aa2fbe7 Dimitris Aragiorgis
    def rs_response(self, arg1, arg2=None):  # pylint: disable=W0613
788 247ad61d Apollon Oikonomopoulos
        """ Generate a reply to a BOOTP/DHCP request
789 247ad61d Apollon Oikonomopoulos
790 247ad61d Apollon Oikonomopoulos
        """
791 fd7ca450 Dimitris Aragiorgis
        logging.info(" * Processing pending RS request")
792 9aa2fbe7 Dimitris Aragiorgis
        # Workaround for supporting both squeezy's nfqueue-bindings-python
793 9aa2fbe7 Dimitris Aragiorgis
        # and wheezy's python-nfqueue because for some reason the function's
794 9aa2fbe7 Dimitris Aragiorgis
        # signature has changed and has broken compatibility
795 9aa2fbe7 Dimitris Aragiorgis
        # See bug http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=718894
796 9aa2fbe7 Dimitris Aragiorgis
        if arg2:
797 9aa2fbe7 Dimitris Aragiorgis
            payload = arg2
798 9aa2fbe7 Dimitris Aragiorgis
        else:
799 9aa2fbe7 Dimitris Aragiorgis
            payload = arg1
800 de1a1bb2 Dimitris Aragiorgis
        pkt = IPv6(payload.get_data())
801 f54e48af Dimitris Aragiorgis
        #logging.debug(pkt.show())
802 3596e9b6 Dimitris Aragiorgis
        try:
803 3596e9b6 Dimitris Aragiorgis
            mac = pkt.lladdr
804 3596e9b6 Dimitris Aragiorgis
        except:
805 0fbb25c0 Dimitris Aragiorgis
            logging.debug(" - Cannot obtain lladdr in rs")
806 3596e9b6 Dimitris Aragiorgis
            return
807 3596e9b6 Dimitris Aragiorgis
808 f54e48af Dimitris Aragiorgis
        indev = get_indev(payload)
809 f54e48af Dimitris Aragiorgis
810 09f11926 Dimitris Aragiorgis
        binding = self.get_binding(indev, mac)
811 f54e48af Dimitris Aragiorgis
        if binding is None:
812 f54e48af Dimitris Aragiorgis
            # We don't know anything about this interface, so accept the packet
813 f54e48af Dimitris Aragiorgis
            # and return
814 0fbb25c0 Dimitris Aragiorgis
            logging.debug(" - Ignoring router solicitation on for mac %s", mac)
815 4c042e71 Apollon Oikonomopoulos
            # We don't know what to do with this packet, so let the kernel
816 4c042e71 Apollon Oikonomopoulos
            # handle it
817 4c042e71 Apollon Oikonomopoulos
            payload.set_verdict(nfqueue.NF_ACCEPT)
818 4c042e71 Apollon Oikonomopoulos
            return
819 4c042e71 Apollon Oikonomopoulos
820 247ad61d Apollon Oikonomopoulos
        # Signal the kernel that it shouldn't further process the packet
821 247ad61d Apollon Oikonomopoulos
        payload.set_verdict(nfqueue.NF_DROP)
822 247ad61d Apollon Oikonomopoulos
823 f54e48af Dimitris Aragiorgis
        if mac != binding.mac:
824 09f11926 Dimitris Aragiorgis
            logging.warn(" - Received spoofed RS request: mac %s, tap %s",
825 98b1900a Christos Stavrakakis
                         mac, binding.tap)
826 f54e48af Dimitris Aragiorgis
            return
827 f54e48af Dimitris Aragiorgis
828 de1a1bb2 Dimitris Aragiorgis
        subnet = binding.net6
829 de1a1bb2 Dimitris Aragiorgis
830 de1a1bb2 Dimitris Aragiorgis
        if subnet.net is None:
831 0fbb25c0 Dimitris Aragiorgis
            logging.debug(" - No IPv6 network assigned for tap %s", binding.tap)
832 764f829a Christos Stavrakakis
            return
833 de1a1bb2 Dimitris Aragiorgis
834 f54e48af Dimitris Aragiorgis
        indevmac = self.get_iface_hw_addr(binding.indev)
835 f54e48af Dimitris Aragiorgis
        ifll = subnet.make_ll64(indevmac)
836 4a3ed624 Dimitris Aragiorgis
        if ifll is None:
837 4a3ed624 Dimitris Aragiorgis
            return
838 de1a1bb2 Dimitris Aragiorgis
839 fd7ca450 Dimitris Aragiorgis
        logging.info(" - Generating RA for host %s (mac %s) on tap %s",
840 0fbb25c0 Dimitris Aragiorgis
                      binding.hostname, mac, binding.tap)
841 0fbb25c0 Dimitris Aragiorgis
842 f54e48af Dimitris Aragiorgis
        resp = Ether(src=indevmac)/\
843 06e6d9bc Dimitris Aragiorgis
               IPv6(src=str(ifll))/ICMPv6ND_RA(O=1, routerlifetime=14400)/\
844 247ad61d Apollon Oikonomopoulos
               ICMPv6NDOptPrefixInfo(prefix=str(subnet.prefix),
845 247ad61d Apollon Oikonomopoulos
                                     prefixlen=subnet.prefixlen)
846 247ad61d Apollon Oikonomopoulos
847 30dd1f9e Apollon Oikonomopoulos
        if self.ipv6_nameservers:
848 30dd1f9e Apollon Oikonomopoulos
            resp /= ICMPv6NDOptRDNSS(dns=self.ipv6_nameservers,
849 30dd1f9e Apollon Oikonomopoulos
                                     lifetime=self.ra_period * 3)
850 30dd1f9e Apollon Oikonomopoulos
851 3596e9b6 Dimitris Aragiorgis
        try:
852 09f11926 Dimitris Aragiorgis
            binding.sendp(resp)
853 3596e9b6 Dimitris Aragiorgis
        except socket.error, e:
854 fd7ca450 Dimitris Aragiorgis
            logging.warn(" - RA on %s (%s) failed: %s",
855 fd7ca450 Dimitris Aragiorgis
                         binding.tap, binding.hostname, str(e))
856 3596e9b6 Dimitris Aragiorgis
        except Exception, e:
857 fd7ca450 Dimitris Aragiorgis
            logging.warn(" - Unkown error during RA on %s (%s): %s",
858 fd7ca450 Dimitris Aragiorgis
                         binding.tap, binding.hostname, str(e))
859 1f3139f3 Apollon Oikonomopoulos
860 9aa2fbe7 Dimitris Aragiorgis
    def ns_response(self, arg1, arg2=None):  # pylint: disable=W0613
861 a5c8c1fe Apollon Oikonomopoulos
        """ Generate a reply to an ICMPv6 neighbor solicitation
862 a5c8c1fe Apollon Oikonomopoulos
863 a5c8c1fe Apollon Oikonomopoulos
        """
864 764f829a Christos Stavrakakis
865 fd7ca450 Dimitris Aragiorgis
        logging.info(" * Processing pending NS request")
866 9aa2fbe7 Dimitris Aragiorgis
        # Workaround for supporting both squeezy's nfqueue-bindings-python
867 9aa2fbe7 Dimitris Aragiorgis
        # and wheezy's python-nfqueue because for some reason the function's
868 9aa2fbe7 Dimitris Aragiorgis
        # signature has changed and has broken compatibility
869 9aa2fbe7 Dimitris Aragiorgis
        # See bug http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=718894
870 9aa2fbe7 Dimitris Aragiorgis
        if arg2:
871 9aa2fbe7 Dimitris Aragiorgis
            payload = arg2
872 9aa2fbe7 Dimitris Aragiorgis
        else:
873 9aa2fbe7 Dimitris Aragiorgis
            payload = arg1
874 0fbb25c0 Dimitris Aragiorgis
875 de1a1bb2 Dimitris Aragiorgis
        ns = IPv6(payload.get_data())
876 3596e9b6 Dimitris Aragiorgis
        #logging.debug(ns.show())
877 3596e9b6 Dimitris Aragiorgis
        try:
878 3596e9b6 Dimitris Aragiorgis
            mac = ns.lladdr
879 3596e9b6 Dimitris Aragiorgis
        except:
880 0fbb25c0 Dimitris Aragiorgis
            logging.debug(" - Cannot obtain lladdr from ns")
881 3596e9b6 Dimitris Aragiorgis
            return
882 de1a1bb2 Dimitris Aragiorgis
883 de1a1bb2 Dimitris Aragiorgis
884 f54e48af Dimitris Aragiorgis
        indev = get_indev(payload)
885 f54e48af Dimitris Aragiorgis
886 09f11926 Dimitris Aragiorgis
        binding = self.get_binding(indev, mac)
887 f54e48af Dimitris Aragiorgis
        if binding is None:
888 f54e48af Dimitris Aragiorgis
            # We don't know anything about this interface, so accept the packet
889 f54e48af Dimitris Aragiorgis
            # and return
890 0fbb25c0 Dimitris Aragiorgis
            logging.debug(" - Ignoring neighbour solicitation for eui64 %s",
891 0fbb25c0 Dimitris Aragiorgis
                          ns.tgt)
892 f54e48af Dimitris Aragiorgis
            # We don't know what to do with this packet, so let the kernel
893 f54e48af Dimitris Aragiorgis
            # handle it
894 f54e48af Dimitris Aragiorgis
            payload.set_verdict(nfqueue.NF_ACCEPT)
895 f54e48af Dimitris Aragiorgis
            return
896 f54e48af Dimitris Aragiorgis
897 f54e48af Dimitris Aragiorgis
        payload.set_verdict(nfqueue.NF_DROP)
898 f54e48af Dimitris Aragiorgis
899 f54e48af Dimitris Aragiorgis
        if mac != binding.mac:
900 0fbb25c0 Dimitris Aragiorgis
            logging.warn(" - Received spoofed NS request"
901 0fbb25c0 Dimitris Aragiorgis
                         " for mac %s from tap %s", mac, binding.tap)
902 f54e48af Dimitris Aragiorgis
            return
903 de1a1bb2 Dimitris Aragiorgis
904 de1a1bb2 Dimitris Aragiorgis
        subnet = binding.net6
905 de1a1bb2 Dimitris Aragiorgis
        if subnet.net is None:
906 0fbb25c0 Dimitris Aragiorgis
            logging.debug(" - No IPv6 network assigned for the interface")
907 764f829a Christos Stavrakakis
            return
908 4c042e71 Apollon Oikonomopoulos
909 de1a1bb2 Dimitris Aragiorgis
        indevmac = self.get_iface_hw_addr(binding.indev)
910 de1a1bb2 Dimitris Aragiorgis
911 de1a1bb2 Dimitris Aragiorgis
        ifll = subnet.make_ll64(indevmac)
912 4a3ed624 Dimitris Aragiorgis
        if ifll is None:
913 4a3ed624 Dimitris Aragiorgis
            return
914 a5c8c1fe Apollon Oikonomopoulos
915 a5c8c1fe Apollon Oikonomopoulos
        if not (subnet.net.overlaps(ns.tgt) or str(ns.tgt) == str(ifll)):
916 0fbb25c0 Dimitris Aragiorgis
            logging.debug(" - Received NS for a non-routable IP (%s)", ns.tgt)
917 a5c8c1fe Apollon Oikonomopoulos
            return 1
918 a5c8c1fe Apollon Oikonomopoulos
919 fd7ca450 Dimitris Aragiorgis
        logging.info(" - Generating NA for host %s (mac %s) on tap %s",
920 fd7ca450 Dimitris Aragiorgis
                     binding.hostname, mac, binding.tap)
921 0fbb25c0 Dimitris Aragiorgis
922 de1a1bb2 Dimitris Aragiorgis
        resp = Ether(src=indevmac, dst=binding.mac)/\
923 a5c8c1fe Apollon Oikonomopoulos
               IPv6(src=str(ifll), dst=ns.src)/\
924 a5c8c1fe Apollon Oikonomopoulos
               ICMPv6ND_NA(R=1, O=0, S=1, tgt=ns.tgt)/\
925 de1a1bb2 Dimitris Aragiorgis
               ICMPv6NDOptDstLLAddr(lladdr=indevmac)
926 a5c8c1fe Apollon Oikonomopoulos
927 3596e9b6 Dimitris Aragiorgis
        try:
928 09f11926 Dimitris Aragiorgis
            binding.sendp(resp)
929 3596e9b6 Dimitris Aragiorgis
        except socket.error, e:
930 fd7ca450 Dimitris Aragiorgis
            logging.warn(" - NA on %s (%s) failed: %s",
931 09f11926 Dimitris Aragiorgis
                         binding.tap, binding.hostname, str(e))
932 3596e9b6 Dimitris Aragiorgis
        except Exception, e:
933 fd7ca450 Dimitris Aragiorgis
            logging.warn(" - Unkown error during periodic NA to %s (%s): %s",
934 fd7ca450 Dimitris Aragiorgis
                         binding.tap, binding.hostname, str(e))
935 a5c8c1fe Apollon Oikonomopoulos
936 fa04d422 Apollon Oikonomopoulos
    def send_periodic_ra(self):
937 83027c6b Apollon Oikonomopoulos
        # Use a separate thread as this may take a _long_ time with
938 83027c6b Apollon Oikonomopoulos
        # many interfaces and we want to be responsive in the mean time
939 83027c6b Apollon Oikonomopoulos
        threading.Thread(target=self._send_periodic_ra).start()
940 83027c6b Apollon Oikonomopoulos
941 83027c6b Apollon Oikonomopoulos
    def _send_periodic_ra(self):
942 fd7ca450 Dimitris Aragiorgis
        logging.info("Sending out periodic RAs")
943 6ca53b5c Apollon Oikonomopoulos
        start = time.time()
944 6ca53b5c Apollon Oikonomopoulos
        i = 0
945 de1a1bb2 Dimitris Aragiorgis
        for binding in self.clients.values():
946 de1a1bb2 Dimitris Aragiorgis
            tap = binding.tap
947 de1a1bb2 Dimitris Aragiorgis
            indev = binding.indev
948 764f829a Christos Stavrakakis
            # mac = binding.mac
949 de1a1bb2 Dimitris Aragiorgis
            subnet = binding.net6
950 b0b3ad51 Apollon Oikonomopoulos
            if subnet.net is None:
951 0fbb25c0 Dimitris Aragiorgis
                logging.debug(" - Skipping periodic RA on interface %s,"
952 de1a1bb2 Dimitris Aragiorgis
                              " as it is not IPv6-connected", tap)
953 b0b3ad51 Apollon Oikonomopoulos
                continue
954 de1a1bb2 Dimitris Aragiorgis
            indevmac = self.get_iface_hw_addr(indev)
955 de1a1bb2 Dimitris Aragiorgis
            ifll = subnet.make_ll64(indevmac)
956 4a3ed624 Dimitris Aragiorgis
            if ifll is None:
957 4a3ed624 Dimitris Aragiorgis
                continue
958 de1a1bb2 Dimitris Aragiorgis
            resp = Ether(src=indevmac)/\
959 fa04d422 Apollon Oikonomopoulos
                   IPv6(src=str(ifll))/ICMPv6ND_RA(routerlifetime=14400)/\
960 fa04d422 Apollon Oikonomopoulos
                   ICMPv6NDOptPrefixInfo(prefix=str(subnet.prefix),
961 fa04d422 Apollon Oikonomopoulos
                                         prefixlen=subnet.prefixlen)
962 30dd1f9e Apollon Oikonomopoulos
            if self.ipv6_nameservers:
963 30dd1f9e Apollon Oikonomopoulos
                resp /= ICMPv6NDOptRDNSS(dns=self.ipv6_nameservers,
964 30dd1f9e Apollon Oikonomopoulos
                                         lifetime=self.ra_period * 3)
965 fa04d422 Apollon Oikonomopoulos
            try:
966 09f11926 Dimitris Aragiorgis
                binding.sendp(resp)
967 810a20fa Apollon Oikonomopoulos
            except socket.error, e:
968 fd7ca450 Dimitris Aragiorgis
                logging.warn(" - Periodic RA on %s (%s) failed: %s",
969 fd7ca450 Dimitris Aragiorgis
                             tap, binding.hostname, str(e))
970 810a20fa Apollon Oikonomopoulos
            except Exception, e:
971 fd7ca450 Dimitris Aragiorgis
                logging.warn(" - Unkown error during periodic RA on %s (%s):"
972 fd7ca450 Dimitris Aragiorgis
                             " %s", tap, binding.hostname, str(e))
973 6ca53b5c Apollon Oikonomopoulos
            i += 1
974 fd7ca450 Dimitris Aragiorgis
        logging.info(" - Sent %d RAs in %.2f seconds", i, time.time() - start)
975 fa04d422 Apollon Oikonomopoulos
976 1f3139f3 Apollon Oikonomopoulos
    def serve(self):
977 36e1175b Apollon Oikonomopoulos
        """ Safely perform the main loop, freeing all resources upon exit
978 36e1175b Apollon Oikonomopoulos
979 36e1175b Apollon Oikonomopoulos
        """
980 36e1175b Apollon Oikonomopoulos
        try:
981 36e1175b Apollon Oikonomopoulos
            self._serve()
982 36e1175b Apollon Oikonomopoulos
        finally:
983 36e1175b Apollon Oikonomopoulos
            self._cleanup()
984 36e1175b Apollon Oikonomopoulos
985 36e1175b Apollon Oikonomopoulos
    def _serve(self):
986 1f3139f3 Apollon Oikonomopoulos
        """ Loop forever, serving DHCP requests
987 1f3139f3 Apollon Oikonomopoulos
988 1f3139f3 Apollon Oikonomopoulos
        """
989 1f3139f3 Apollon Oikonomopoulos
        self.build_config()
990 1f3139f3 Apollon Oikonomopoulos
991 26ba9dba Costas Drogos
        # Yes, we are accessing _fd directly, but it's the only way to have a
992 6765a36f Apollon Oikonomopoulos
        # single select() loop ;-)
993 764f829a Christos Stavrakakis
        iwfd = self.notifier._fd  # pylint: disable=W0212
994 1f3139f3 Apollon Oikonomopoulos
995 f4b0c05f Apollon Oikonomopoulos
        start = time.time()
996 31d21144 Apollon Oikonomopoulos
        if self.ipv6_enabled:
997 31d21144 Apollon Oikonomopoulos
            timeout = self.ra_period
998 31d21144 Apollon Oikonomopoulos
            self.send_periodic_ra()
999 31d21144 Apollon Oikonomopoulos
        else:
1000 31d21144 Apollon Oikonomopoulos
            timeout = None
1001 fa04d422 Apollon Oikonomopoulos
1002 1f3139f3 Apollon Oikonomopoulos
        while True:
1003 40a561a7 Dimitris Aragiorgis
            try:
1004 09f11926 Dimitris Aragiorgis
                rlist, _, xlist = select.select(self.nfq.keys() + [iwfd],
1005 09f11926 Dimitris Aragiorgis
                                                [], [], timeout)
1006 40a561a7 Dimitris Aragiorgis
            except select.error, e:
1007 40a561a7 Dimitris Aragiorgis
                if e[0] == errno.EINTR:
1008 40a561a7 Dimitris Aragiorgis
                    logging.debug("select() got interrupted")
1009 40a561a7 Dimitris Aragiorgis
                    continue
1010 40a561a7 Dimitris Aragiorgis
1011 bf84c4a5 Apollon Oikonomopoulos
            if xlist:
1012 6765a36f Apollon Oikonomopoulos
                logging.warn("Warning: Exception on %s",
1013 764f829a Christos Stavrakakis
                             ", ".join([str(fd) for fd in xlist]))
1014 bf84c4a5 Apollon Oikonomopoulos
1015 41a0f754 Apollon Oikonomopoulos
            if rlist:
1016 f4b0c05f Apollon Oikonomopoulos
                if iwfd in rlist:
1017 41a0f754 Apollon Oikonomopoulos
                # First check if there are any inotify (= configuration change)
1018 41a0f754 Apollon Oikonomopoulos
                # events
1019 f4b0c05f Apollon Oikonomopoulos
                    self.notifier.read_events()
1020 f4b0c05f Apollon Oikonomopoulos
                    self.notifier.process_events()
1021 f4b0c05f Apollon Oikonomopoulos
                    rlist.remove(iwfd)
1022 1f3139f3 Apollon Oikonomopoulos
1023 0fbb25c0 Dimitris Aragiorgis
                logging.debug("Pending requests on fds %s", rlist)
1024 0fbb25c0 Dimitris Aragiorgis
1025 f4b0c05f Apollon Oikonomopoulos
                for fd in rlist:
1026 bf84c4a5 Apollon Oikonomopoulos
                    try:
1027 3f442273 Dimitris Aragiorgis
                        q, num = self.nfq[fd]
1028 3f442273 Dimitris Aragiorgis
                        cnt = q.process_pending(num)
1029 0fbb25c0 Dimitris Aragiorgis
                        logging.debug(" * Processed %d requests on NFQUEUE"
1030 0fbb25c0 Dimitris Aragiorgis
                                      " with fd %d", cnt, fd)
1031 6765a36f Apollon Oikonomopoulos
                    except RuntimeError, e:
1032 6765a36f Apollon Oikonomopoulos
                        logging.warn("Error processing fd %d: %s", fd, str(e))
1033 810a20fa Apollon Oikonomopoulos
                    except Exception, e:
1034 6765a36f Apollon Oikonomopoulos
                        logging.warn("Unknown error processing fd %d: %s",
1035 6765a36f Apollon Oikonomopoulos
                                     fd, str(e))
1036 1f3139f3 Apollon Oikonomopoulos
1037 31d21144 Apollon Oikonomopoulos
            if self.ipv6_enabled:
1038 31d21144 Apollon Oikonomopoulos
                # Calculate the new timeout
1039 ea915b1a Apollon Oikonomopoulos
                timeout = self.ra_period - (time.time() - start)
1040 fa04d422 Apollon Oikonomopoulos
1041 31d21144 Apollon Oikonomopoulos
                if timeout <= 0:
1042 31d21144 Apollon Oikonomopoulos
                    start = time.time()
1043 31d21144 Apollon Oikonomopoulos
                    self.send_periodic_ra()
1044 31d21144 Apollon Oikonomopoulos
                    timeout = self.ra_period - (time.time() - start)
1045 1f3139f3 Apollon Oikonomopoulos
1046 40a561a7 Dimitris Aragiorgis
    def print_clients(self):
1047 09f11926 Dimitris Aragiorgis
        logging.info("%10s   %20s %20s %10s %20s",
1048 09f11926 Dimitris Aragiorgis
                     'Key', 'Client', 'MAC', 'TAP', 'IP')
1049 40a561a7 Dimitris Aragiorgis
        for k, cl in self.clients.items():
1050 09f11926 Dimitris Aragiorgis
            logging.info("%10s | %20s %20s %10s %20s",
1051 09f11926 Dimitris Aragiorgis
                         k, cl.hostname, cl.mac, cl.tap, cl.ip)
1052 40a561a7 Dimitris Aragiorgis
1053 40a561a7 Dimitris Aragiorgis
1054 f4b0c05f Apollon Oikonomopoulos
1055 1f3139f3 Apollon Oikonomopoulos
if __name__ == "__main__":
1056 6765a36f Apollon Oikonomopoulos
    import capng
1057 1f3139f3 Apollon Oikonomopoulos
    import optparse
1058 651e531d Apollon Oikonomopoulos
    from cStringIO import StringIO
1059 1f3139f3 Apollon Oikonomopoulos
    from pwd import getpwnam, getpwuid
1060 810a20fa Apollon Oikonomopoulos
    from configobj import ConfigObj, ConfigObjError, flatten_errors
1061 651e531d Apollon Oikonomopoulos
1062 651e531d Apollon Oikonomopoulos
    import validate
1063 651e531d Apollon Oikonomopoulos
1064 651e531d Apollon Oikonomopoulos
    validator = validate.Validator()
1065 651e531d Apollon Oikonomopoulos
1066 651e531d Apollon Oikonomopoulos
    def is_ip_list(value, family=4):
1067 651e531d Apollon Oikonomopoulos
        try:
1068 651e531d Apollon Oikonomopoulos
            family = int(family)
1069 651e531d Apollon Oikonomopoulos
        except ValueError:
1070 c63ad0e2 Apollon Oikonomopoulos
            raise validate.VdtParamError(family)
1071 651e531d Apollon Oikonomopoulos
        if isinstance(value, (str, unicode)):
1072 651e531d Apollon Oikonomopoulos
            value = [value]
1073 651e531d Apollon Oikonomopoulos
        if not isinstance(value, list):
1074 651e531d Apollon Oikonomopoulos
            raise validate.VdtTypeError(value)
1075 651e531d Apollon Oikonomopoulos
1076 651e531d Apollon Oikonomopoulos
        for entry in value:
1077 651e531d Apollon Oikonomopoulos
            try:
1078 651e531d Apollon Oikonomopoulos
                ip = IPy.IP(entry)
1079 651e531d Apollon Oikonomopoulos
            except ValueError:
1080 651e531d Apollon Oikonomopoulos
                raise validate.VdtValueError(entry)
1081 651e531d Apollon Oikonomopoulos
1082 651e531d Apollon Oikonomopoulos
            if ip.version() != family:
1083 651e531d Apollon Oikonomopoulos
                raise validate.VdtValueError(entry)
1084 651e531d Apollon Oikonomopoulos
        return value
1085 651e531d Apollon Oikonomopoulos
1086 651e531d Apollon Oikonomopoulos
    validator.functions["ip_addr_list"] = is_ip_list
1087 651e531d Apollon Oikonomopoulos
    config_spec = StringIO(CONFIG_SPEC)
1088 651e531d Apollon Oikonomopoulos
1089 1f3139f3 Apollon Oikonomopoulos
    parser = optparse.OptionParser()
1090 ea915b1a Apollon Oikonomopoulos
    parser.add_option("-c", "--config", dest="config_file",
1091 ea915b1a Apollon Oikonomopoulos
                      help="The location of the data files", metavar="FILE",
1092 ea915b1a Apollon Oikonomopoulos
                      default=DEFAULT_CONFIG)
1093 1f3139f3 Apollon Oikonomopoulos
    parser.add_option("-d", "--debug", action="store_true", dest="debug",
1094 1f3139f3 Apollon Oikonomopoulos
                      help="Turn on debugging messages")
1095 0679a724 Apollon Oikonomopoulos
    parser.add_option("-f", "--foreground", action="store_false",
1096 0679a724 Apollon Oikonomopoulos
                      dest="daemonize", default=True,
1097 0679a724 Apollon Oikonomopoulos
                      help="Do not daemonize, stay in the foreground")
1098 1f3139f3 Apollon Oikonomopoulos
1099 1f3139f3 Apollon Oikonomopoulos
    opts, args = parser.parse_args()
1100 1f3139f3 Apollon Oikonomopoulos
1101 ea915b1a Apollon Oikonomopoulos
    try:
1102 651e531d Apollon Oikonomopoulos
        config = ConfigObj(opts.config_file, configspec=config_spec)
1103 6765a36f Apollon Oikonomopoulos
    except ConfigObjError, err:
1104 810a20fa Apollon Oikonomopoulos
        sys.stderr.write("Failed to parse config file %s: %s" %
1105 6765a36f Apollon Oikonomopoulos
                         (opts.config_file, str(err)))
1106 ea915b1a Apollon Oikonomopoulos
        sys.exit(1)
1107 ea915b1a Apollon Oikonomopoulos
1108 651e531d Apollon Oikonomopoulos
    results = config.validate(validator)
1109 651e531d Apollon Oikonomopoulos
    if results != True:
1110 651e531d Apollon Oikonomopoulos
        logging.fatal("Configuration file validation failed! See errors below:")
1111 6765a36f Apollon Oikonomopoulos
        for (section_list, key, unused) in flatten_errors(config, results):
1112 651e531d Apollon Oikonomopoulos
            if key is not None:
1113 6765a36f Apollon Oikonomopoulos
                logging.fatal(" '%s' in section '%s' failed validation",
1114 6765a36f Apollon Oikonomopoulos
                              key, ", ".join(section_list))
1115 651e531d Apollon Oikonomopoulos
            else:
1116 6765a36f Apollon Oikonomopoulos
                logging.fatal(" Section '%s' is missing",
1117 0679a724 Apollon Oikonomopoulos
                              ", ".join(section_list))
1118 651e531d Apollon Oikonomopoulos
        sys.exit(1)
1119 ea915b1a Apollon Oikonomopoulos
1120 de311515 Dimitris Aragiorgis
    try:
1121 de311515 Dimitris Aragiorgis
        uid = getpwuid(config["general"].as_int("user"))
1122 de311515 Dimitris Aragiorgis
    except ValueError:
1123 de311515 Dimitris Aragiorgis
        uid = getpwnam(config["general"]["user"])
1124 de311515 Dimitris Aragiorgis
1125 de311515 Dimitris Aragiorgis
    # Keep only the capabilities we need
1126 de311515 Dimitris Aragiorgis
    # CAP_NET_ADMIN: we need to send nfqueue packet verdicts to a netlinkgroup
1127 de311515 Dimitris Aragiorgis
    # CAP_NET_RAW: we need to reopen socket in case the buffer gets full
1128 de311515 Dimitris Aragiorgis
    # CAP_SETPCAP: needed by capng_change_id()
1129 de311515 Dimitris Aragiorgis
    capng.capng_clear(capng.CAPNG_SELECT_BOTH)
1130 de311515 Dimitris Aragiorgis
    capng.capng_update(capng.CAPNG_ADD,
1131 de311515 Dimitris Aragiorgis
                       capng.CAPNG_EFFECTIVE | capng.CAPNG_PERMITTED,
1132 de311515 Dimitris Aragiorgis
                       capng.CAP_NET_ADMIN)
1133 de311515 Dimitris Aragiorgis
    capng.capng_update(capng.CAPNG_ADD,
1134 de311515 Dimitris Aragiorgis
                       capng.CAPNG_EFFECTIVE | capng.CAPNG_PERMITTED,
1135 de311515 Dimitris Aragiorgis
                       capng.CAP_NET_RAW)
1136 de311515 Dimitris Aragiorgis
    capng.capng_update(capng.CAPNG_ADD,
1137 de311515 Dimitris Aragiorgis
                       capng.CAPNG_EFFECTIVE | capng.CAPNG_PERMITTED,
1138 de311515 Dimitris Aragiorgis
                       capng.CAP_SETPCAP)
1139 de311515 Dimitris Aragiorgis
    # change uid
1140 de311515 Dimitris Aragiorgis
    capng.capng_change_id(uid.pw_uid, uid.pw_gid,
1141 09f11926 Dimitris Aragiorgis
                          capng.CAPNG_DROP_SUPP_GRP | \
1142 09f11926 Dimitris Aragiorgis
                          capng.CAPNG_CLEAR_BOUNDING)
1143 de311515 Dimitris Aragiorgis
1144 1f3139f3 Apollon Oikonomopoulos
    logger = logging.getLogger()
1145 1f3139f3 Apollon Oikonomopoulos
    if opts.debug:
1146 1f3139f3 Apollon Oikonomopoulos
        logger.setLevel(logging.DEBUG)
1147 1f3139f3 Apollon Oikonomopoulos
    else:
1148 1f3139f3 Apollon Oikonomopoulos
        logger.setLevel(logging.INFO)
1149 1f3139f3 Apollon Oikonomopoulos
1150 df3e8fac Vangelis Koukis
    if opts.daemonize:
1151 df3e8fac Vangelis Koukis
        logfile = os.path.join(config["general"]["logdir"], LOG_FILENAME)
1152 0a2aed6e Dimitris Aragiorgis
        handler = logging.handlers.WatchedFileHandler(logfile)
1153 df3e8fac Vangelis Koukis
    else:
1154 df3e8fac Vangelis Koukis
        handler = logging.StreamHandler()
1155 df3e8fac Vangelis Koukis
1156 df3e8fac Vangelis Koukis
    handler.setFormatter(logging.Formatter(LOG_FORMAT))
1157 df3e8fac Vangelis Koukis
    logger.addHandler(handler)
1158 df3e8fac Vangelis Koukis
1159 856268f2 Vangelis Koukis
    # Rename this process so 'ps' output looks like
1160 b53b8522 Vangelis Koukis
    # this is a native executable.
1161 b53b8522 Vangelis Koukis
    # NOTE: due to a bug in python-setproctitle, one cannot yet
1162 b53b8522 Vangelis Koukis
    # set individual values for command-line arguments, so only show
1163 b53b8522 Vangelis Koukis
    # the name of the executable instead.
1164 b53b8522 Vangelis Koukis
    # setproctitle.setproctitle("\x00".join(sys.argv))
1165 b53b8522 Vangelis Koukis
    setproctitle.setproctitle(sys.argv[0])
1166 856268f2 Vangelis Koukis
1167 df3e8fac Vangelis Koukis
    if opts.daemonize:
1168 dfe6cc3b Costas Drogos
        pidfile = daemon.pidlockfile.TimeoutPIDLockFile(
1169 df3e8fac Vangelis Koukis
            config["general"]["pidfile"], 10)
1170 d9361b6e Dimitris Aragriorgs
        # Remove any stale PID files, left behind by previous invocations
1171 0c650606 Dimitris Aragriorgs
        if daemon.runner.is_pidfile_stale(pidfile):
1172 d9361b6e Dimitris Aragriorgs
            logger.warning("Removing stale PID lock file %s", pidfile.path)
1173 d9361b6e Dimitris Aragriorgs
            pidfile.break_lock()
1174 d9361b6e Dimitris Aragriorgs
1175 df3e8fac Vangelis Koukis
        d = daemon.DaemonContext(pidfile=pidfile,
1176 d7b852fd Christos Stavrakakis
                                 umask=0022,
1177 df3e8fac Vangelis Koukis
                                 stdout=handler.stream,
1178 df3e8fac Vangelis Koukis
                                 stderr=handler.stream,
1179 df3e8fac Vangelis Koukis
                                 files_preserve=[handler.stream])
1180 883eb77e Dimitris Aragriorgs
        try:
1181 883eb77e Dimitris Aragriorgs
            d.open()
1182 883eb77e Dimitris Aragriorgs
        except (daemon.pidlockfile.AlreadyLocked, LockTimeout):
1183 883eb77e Dimitris Aragriorgs
            logger.critical("Failed to lock pidfile %s,"
1184 883eb77e Dimitris Aragriorgs
                            " another instance running?", pidfile.path)
1185 883eb77e Dimitris Aragriorgs
            sys.exit(1)
1186 df3e8fac Vangelis Koukis
1187 1f3139f3 Apollon Oikonomopoulos
    logging.info("Starting up")
1188 de311515 Dimitris Aragiorgis
    logging.info("Running as %s (uid:%d, gid: %d)",
1189 de311515 Dimitris Aragiorgis
                  config["general"]["user"], uid.pw_uid, uid.pw_gid)
1190 ea915b1a Apollon Oikonomopoulos
1191 ea915b1a Apollon Oikonomopoulos
    proxy_opts = {}
1192 ea915b1a Apollon Oikonomopoulos
    if config["dhcp"].as_bool("enable_dhcp"):
1193 ea915b1a Apollon Oikonomopoulos
        proxy_opts.update({
1194 ea915b1a Apollon Oikonomopoulos
            "dhcp_queue_num": config["dhcp"].as_int("dhcp_queue"),
1195 ea915b1a Apollon Oikonomopoulos
            "dhcp_lease_lifetime": config["dhcp"].as_int("lease_lifetime"),
1196 ea915b1a Apollon Oikonomopoulos
            "dhcp_lease_renewal": config["dhcp"].as_int("lease_renewal"),
1197 ea915b1a Apollon Oikonomopoulos
            "dhcp_server_ip": config["dhcp"]["server_ip"],
1198 ea915b1a Apollon Oikonomopoulos
            "dhcp_nameservers": config["dhcp"]["nameservers"],
1199 7d38c21d Dimitris Aragiorgis
            "dhcp_domain": config["dhcp"]["domain"],
1200 ea915b1a Apollon Oikonomopoulos
        })
1201 ea915b1a Apollon Oikonomopoulos
1202 ea915b1a Apollon Oikonomopoulos
    if config["ipv6"].as_bool("enable_ipv6"):
1203 ea915b1a Apollon Oikonomopoulos
        proxy_opts.update({
1204 06e6d9bc Dimitris Aragiorgis
            "dhcpv6_queue_num": config["ipv6"].as_int("dhcp_queue"),
1205 ea915b1a Apollon Oikonomopoulos
            "rs_queue_num": config["ipv6"].as_int("rs_queue"),
1206 ea915b1a Apollon Oikonomopoulos
            "ns_queue_num": config["ipv6"].as_int("ns_queue"),
1207 ea915b1a Apollon Oikonomopoulos
            "ra_period": config["ipv6"].as_int("ra_period"),
1208 ea915b1a Apollon Oikonomopoulos
            "ipv6_nameservers": config["ipv6"]["nameservers"],
1209 7b0ebdd0 Dimitris Aragiorgis
            "dhcpv6_domains": config["ipv6"]["domains"],
1210 ea915b1a Apollon Oikonomopoulos
        })
1211 ea915b1a Apollon Oikonomopoulos
1212 6765a36f Apollon Oikonomopoulos
    # pylint: disable=W0142
1213 ea915b1a Apollon Oikonomopoulos
    proxy = VMNetProxy(data_path=config["general"]["datapath"], **proxy_opts)
1214 1f3139f3 Apollon Oikonomopoulos
1215 1f3139f3 Apollon Oikonomopoulos
    logging.info("Ready to serve requests")
1216 40a561a7 Dimitris Aragiorgis
1217 40a561a7 Dimitris Aragiorgis
1218 09f11926 Dimitris Aragiorgis
    def debug_handler(signum, _):
1219 09f11926 Dimitris Aragiorgis
        logging.debug('Received signal %d. Printing proxy state...', signum)
1220 40a561a7 Dimitris Aragiorgis
        proxy.print_clients()
1221 40a561a7 Dimitris Aragiorgis
1222 40a561a7 Dimitris Aragiorgis
    # Set the signal handler for debuging clients
1223 09f11926 Dimitris Aragiorgis
    signal.signal(signal.SIGUSR1, debug_handler)
1224 40a561a7 Dimitris Aragiorgis
    signal.siginterrupt(signal.SIGUSR1, False)
1225 40a561a7 Dimitris Aragiorgis
1226 feca7bb9 Apollon Oikonomopoulos
    try:
1227 feca7bb9 Apollon Oikonomopoulos
        proxy.serve()
1228 feca7bb9 Apollon Oikonomopoulos
    except Exception:
1229 feca7bb9 Apollon Oikonomopoulos
        if opts.daemonize:
1230 feca7bb9 Apollon Oikonomopoulos
            exc = "".join(traceback.format_exception(*sys.exc_info()))
1231 feca7bb9 Apollon Oikonomopoulos
            logging.critical(exc)
1232 feca7bb9 Apollon Oikonomopoulos
        raise
1233 1f3139f3 Apollon Oikonomopoulos
1234 1f3139f3 Apollon Oikonomopoulos
1235 1f3139f3 Apollon Oikonomopoulos
# vim: set ts=4 sts=4 sw=4 et :