4
# dnet Python bindings.
6
# Copyright (c) 2003 Dug Song <dugsong@monkey.org>
8
# $Id: dnet.pyx,v 1.9 2004/05/14 04:29:27 dugsong Exp $
10
"""dumb networking library
12
This module provides a simplified interface to several low-level
13
networking routines, including network address manipulation, kernel
14
arp(4) cache and route(4) table lookup and manipulation, network
15
firewalling, network interface lookup and manipulation, and raw IP
16
packet and Ethernet frame transmission.
19
cdef extern from "dnet.h":
22
cdef extern from "Python.h":
23
object PyString_FromStringAndSize(char *s, int len)
24
int PyString_Size(object o)
27
void *memcpy(char *dst, char *src, int len)
28
void *memset(char *b, int c, int len)
29
char *strerror(int errnum)
30
int strlcpy(char *dst, char *src, int size)
32
cdef __memcpy(char *dst, object src, int n):
33
if PyString_Size(src) != n:
34
raise ValueError, "not a %d-byte binary string: %s" % (n, src)
39
return strerror(errno)
45
ctypedef struct eth_t:
47
ctypedef struct eth_addr_t:
50
eth_t *eth_open(char *device)
51
int eth_get(eth_t *eth, eth_addr_t *ea)
52
int eth_set(eth_t *eth, eth_addr_t *ea)
53
int eth_send(eth_t *eth, char *buf, int len)
54
eth_t *eth_close(eth_t *eth)
56
char *__eth_ntoa "eth_ntoa" (eth_addr_t *buf)
57
int __eth_aton "eth_aton" (char *src, eth_addr_t *dst)
58
void __eth_pack_hdr "eth_pack_hdr" (char *h,
59
eth_addr_t dst, eth_addr_t src, int type)
67
ETH_LEN_MIN = 64 # /* minimum frame length with CRC */
68
ETH_LEN_MAX = 1518 # /* maximum frame length with CRC */
70
ETH_MTU = (ETH_LEN_MAX - ETH_HDR_LEN - ETH_CRC_LEN)
71
ETH_MIN = (ETH_LEN_MIN - ETH_HDR_LEN - ETH_CRC_LEN)
73
ETH_TYPE_PUP = 0x0200 # /* PUP protocol */
74
ETH_TYPE_IP = 0x0800 # /* IP protocol */
75
ETH_TYPE_ARP = 0x0806 # /* address resolution protocol */
76
ETH_TYPE_REVARP=0x8035 # /* reverse addr resolution protocol */
77
ETH_TYPE_8021Q =0x8100 # /* IEEE 802.1Q VLAN tagging */
78
ETH_TYPE_IPV6 = 0x86DD # /* IPv6 protocol */
79
ETH_TYPE_MPLS = 0x8847 # /* MPLS */
80
ETH_TYPE_MPLS_MCAST = 0x8848 # /* MPLS Multicast */
81
ETH_TYPE_PPPOEDISC = 0x8863 # /* PPP Over Ethernet Discovery Stage */
82
ETH_TYPE_PPPOE = 0x8864 # /* PPP Over Ethernet Session Stage */
83
ETH_TYPE_LOOPBACK = 0x9000 # /* used to test interfaces */
85
ETH_ADDR_UNSPEC = PyString_FromStringAndSize("\x00\x00\x00\x00\x00\x00", 6)
86
ETH_ADDR_BROADCAST = PyString_FromStringAndSize("\xff\xff\xff\xff\xff\xff", 6)
89
"""eth(device) -> Ethernet device object
91
Open the specified Ethernet device for sending.
95
def __init__(self, device):
96
self.eth = eth_open(device)
98
raise OSError, __oserror()
101
"""Return the MAC address associated with the device as a
104
if eth_get(self.eth, &ea) < 0:
105
raise OSError, __oserror()
106
return PyString_FromStringAndSize(ea.data, 6)
108
def set(self, value):
109
"""Set the MAC address for the device, returning 0 on success,
113
eth_addr -- 6-byte binary string (e.g. '\\x00\\xde\\xad\\xbe\\xef\\x00')
116
__memcpy(ea.data, value, 6)
117
if eth_set(self.eth, &ea) < 0:
118
raise OSError, __oserror()
120
def send(self, frame):
121
"""Send an Ethernet frame, returning the number of bytes sent
125
frame -- binary string representing an Ethernet frame
127
return eth_send(self.eth, frame, PyString_Size(frame))
133
"""Convert an Ethernet MAC address from 6-byte packed binary string to
134
a printable string ('00:de:ad:be:ef:00')."""
136
__memcpy(ea.data, buf, 6)
137
return __eth_ntoa(&ea)
140
"""Convert an Ethernet MAC address from a printable string to a
141
packed binary string ('\\x00\\xde\\xad\\xbe\\xef\\x00')."""
143
if __eth_aton(buf, &ea) < 0:
144
raise ValueError, "invalid Ethernet address"
145
return PyString_FromStringAndSize(ea.data, 6)
147
def eth_pack_hdr(dst=ETH_ADDR_BROADCAST, src=ETH_ADDR_BROADCAST,
149
"""Return a packed binary string representing an Ethernet header.
152
dst -- destination address (6-byte binary string)
153
src -- source address (6-byte binary string)
154
type -- Ethernet payload type (ETH_TYPE_*) (16-bit integer)
158
__memcpy(s.data, src, 6)
159
__memcpy(d.data, dst, 6)
160
__eth_pack_hdr(hdr, d, s, type)
161
return PyString_FromStringAndSize(hdr, 14)
167
ctypedef struct ip_t:
169
ctypedef struct ip_addr_t:
173
int ip_send(ip_t *ip, char *buf, int len)
174
ip_t *ip_close(ip_t *ip)
176
char *__ip_ntoa "ip_ntoa" (ip_addr_t *buf)
177
int __ip_aton "ip_aton" (char *src, ip_addr_t *dst)
178
void __ip_checksum "ip_checksum" (char *buf, int len)
179
void __ip_pack_hdr "ip_pack_hdr" (char *h, int tos, int len, int id,
180
int off, int ttl, int p, ip_addr_t s, ip_addr_t d)
182
IP_ADDR_LEN = 4 # /* IP address length */
183
IP_ADDR_BITS = 32 # /* IP address bits */
185
IP_HDR_LEN = 20 # /* base IP header length */
186
IP_OPT_LEN = 2 # /* base IP option length */
188
IP_HDR_LEN_MAX =(IP_HDR_LEN + IP_OPT_LEN_MAX)
191
IP_LEN_MIN = IP_HDR_LEN
193
IP_TOS_DEFAULT =0x00 # /* default */
195
IP_RF = 0x8000 # /* reserved */
196
IP_DF = 0x4000 # /* don't fragment */
197
IP_MF = 0x2000 # /* more fragments (not last frag) */
198
IP_OFFMASK = 0x1fff # /* mask for fragment offset */
200
IP_TTL_DEFAULT =64 # /* default ttl, RFC 1122, RFC 1340 */
201
IP_TTL_MAX = 255 # /* maximum ttl */
203
IP_PROTO_IP = 0 # /* dummy for IP */
204
IP_PROTO_ICMP = 1 # /* ICMP */
205
IP_PROTO_IGMP = 2 # /* IGMP */
206
IP_PROTO_TCP = 6 # /* TCP */
207
IP_PROTO_UDP = 17 # /* UDP */
208
IP_PROTO_IPV6 = 41 # /* IPv6 */
209
IP_PROTO_GRE = 47 # /* General Routing Encap */
210
IP_PROTO_ESP = 50 # /* Encap Security Payload */
211
IP_PROTO_AH = 51 # /* Authentication Header */
212
IP_PROTO_ICMPV6 = 58 # /* ICMP for IPv6 */
213
IP_PROTO_RAW = 255 # /* Raw IP packets */
214
IP_PROTO_RESERVED = IP_PROTO_RAW # /* Reserved */
217
IP_ADDR_ANY = PyString_FromStringAndSize("\x00\x00\x00\x00", 4)
218
IP_ADDR_BROADCAST = PyString_FromStringAndSize("\xff\xff\xff\xff", 4)
219
IP_ADDR_LOOPBACK = PyString_FromStringAndSize("\x7f\x00\x00\x01", 4)
220
IP_ADDR_MCAST_ALL = PyString_FromStringAndSize("\xe0\x00\x00\x01", 4)
221
IP_ADDR_MCAST_LOCAL = PyString_FromStringAndSize("\xe0\x00\x00\xff", 4)
224
"""ip() -> Raw IP object
226
Open a raw IP socket for sending.
233
raise OSError, __oserror()
236
"""Send an IP packet, returning the number of bytes sent
240
pkt -- binary string representing an IP packet
242
return ip_send(self.ip, pkt, PyString_Size(pkt))
248
"""Convert an IP address from a 4-byte packed binary string to a
249
printable string ('10.0.0.1')."""
251
__memcpy(<char *>&ia, buf, 4)
252
return __ip_ntoa(&ia)
255
"""Convert an IP address from a printable string to a
256
packed binary string ('\\x0a\\x00\\x00\\x01')."""
258
if __ip_aton(buf, &ia) < 0:
259
raise ValueError, "invalid IP address"
260
return PyString_FromStringAndSize(<char *>&ia, 4)
262
def ip_checksum(buf):
263
"""Return a packed binary string representing an IP packet
264
with the IP and transport-layer checksums set.
267
pkt -- binary string representing an IP packet
269
__ip_checksum(buf, PyString_Size(buf))
272
def ip_pack_hdr(tos=IP_TOS_DEFAULT, len=IP_HDR_LEN, id=0, off=0,
273
ttl=IP_TTL_DEFAULT, p=IP_PROTO_IP,
274
src=IP_ADDR_ANY, dst=IP_ADDR_ANY):
275
"""Return a packed binary string representing an IP header.
278
tos -- type of service (8-bit integer)
279
len -- length (IP_HDR_LEN + payload) (16-bit integer)
280
id -- packet ID (16-bit integer)
281
off -- fragmentation offset (16-bit integer)
282
ttl -- time-to-live (8-bit integer)
283
p -- protocol (IP_PROTO_*) (8-bit integer)
284
src -- source address (4-byte binary string)
285
dst -- destination address (4-byte binary string)
289
__memcpy(<char *>&s, src, 4)
290
__memcpy(<char *>&d, dst, 4)
291
__ip_pack_hdr(hdr, tos, len, id, off, ttl, p, s, d)
292
return PyString_FromStringAndSize(hdr, 20)
298
ctypedef struct ip6_addr_t:
301
char *__ip6_ntoa "ip6_ntoa" (ip6_addr_t *buf)
302
int __ip6_aton "ip6_aton" (char *src, ip6_addr_t *dst)
303
void __ip6_checksum "ip6_checksum" (char *buf, int len)
304
void __ip6_pack_hdr "ip6_pack_hdr" (char *h, int fd, int fl, int plen,
305
int nxt, int hlim, ip6_addr_t s, ip6_addr_t d)
310
IP6_HDR_LEN = 40 # /* IPv6 header length */
311
IP6_LEN_MIN = IP6_HDR_LEN
312
IP6_LEN_MAX = 65535 # /* non-jumbo payload */
314
IP6_MTU_MIN = 1280 # /* minimum MTU (1024 + 256) */
319
IP6_ADDR_UNSPEC = PyString_FromStringAndSize("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)
320
IP6_ADDR_LOOPBACK = PyString_FromStringAndSize("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16)
323
"""Convert an IPv6 address from a 16-byte packed binary string to a
324
printable string ('10.0.0.1')."""
326
__memcpy(<char *>&ia, buf, 16)
327
return __ip6_ntoa(&ia)
330
"""Convert an IPv6 address from a printable string to a
331
packed binary string ('\\x0a\\x00\\x00\\x01')."""
333
if __ip6_aton(buf, &ia) < 0:
334
raise ValueError, "invalid IPv6 address"
335
return PyString_FromStringAndSize(<char *>&ia, 16)
337
def ip6_checksum(buf):
338
"""Return a packed binary string representing an IPv6 packet
339
with the IPv6 and transport-layer checksums set.
342
pkt -- binary string representing an IPv6 packet
344
__ip6_checksum(buf, PyString_Size(buf))
347
def ip6_pack_hdr(fc=0, fl=0, plen=0, nxt=IP_PROTO_IPV6, hlim=IP6_HLIM_DEFAULT,
348
src=IP6_ADDR_UNSPEC, dst=IP6_ADDR_UNSPEC):
349
"""Return a packed binary string representing an IPv6 header.
352
fc -- flow class (8-bit integer)
353
fl -- flow label (20-bit integer)
354
plen -- payload length (16-bit integer)
355
nxt -- next header (IP_PROTO_*) (8-bit integer)
356
hlim -- hop limit (8-bit integer)
357
src -- source address (16-byte binary string)
358
dst -- destination address (16-byte binary string)
362
__memcpy(<char *>&s, src, 16)
363
__memcpy(<char *>&d, dst, 16)
364
__ip6_pack_hdr(hdr, fc, fl, plen, nxt, hlim, s, d)
365
return PyString_FromStringAndSize(hdr, 40)
371
cdef struct addr_t "addr":
372
unsigned short addr_type
373
unsigned short addr_bits
376
int addr_cmp(addr_t *a, addr_t *b)
377
int addr_bcast(addr_t *a, addr_t *b)
378
int addr_net(addr_t *a, addr_t *b)
379
char *addr_ntoa(addr_t *a)
380
int addr_aton(char *src, addr_t *dst)
388
"""addr(addrtxt=None) -> network address object
390
Create a network address object (optionally from its human-readable
391
representation). Ethernet, IP, and IPv6 address types are currently
396
def __init__(self, addrtxt=None):
397
if addrtxt != None and addr_aton(addrtxt, &self._addr) < 0:
398
raise ValueError, "invalid network address"
401
"""Address type (ADDR_TYPE_*) integer."""
403
return self._addr.addr_type
404
def __set__(self, unsigned int value):
405
if value > 0xffff: raise OverflowError
406
self._addr.addr_type = value
409
"""Address bitlength integer."""
411
return self._addr.addr_bits
412
def __set__(self, unsigned int value):
413
if value > 0xffff: raise OverflowError
414
self._addr.addr_bits = value
417
"""Ethernet MAC address as binary string."""
419
if self._addr.addr_type != ADDR_TYPE_ETH:
420
raise ValueError, "non-Ethernet address"
421
return PyString_FromStringAndSize(self._addr.addr_data8, 6)
423
def __set__(self, value):
424
if self._addr.addr_type != ADDR_TYPE_ETH:
425
raise ValueError, "non-Ethernet address"
426
__memcpy(self._addr.addr_data8, value, 6)
429
"""IPv4 address as binary string."""
431
if self._addr.addr_type != ADDR_TYPE_IP:
432
raise ValueError, "non-IP address"
433
return PyString_FromStringAndSize(self._addr.addr_data8, 4)
435
def __set__(self, value):
436
if self._addr.addr_type != ADDR_TYPE_IP:
437
raise ValueError, "non-IP address"
438
__memcpy(self._addr.addr_data8, value, 4)
441
"""IPv6 address as binary string."""
443
if self._addr.addr_type != ADDR_TYPE_IP6:
444
raise ValueError, "non-IPv6 address"
445
return PyString_FromStringAndSize(self._addr.addr_data8, 16)
447
def __set__(self, value):
448
if self._addr.addr_type != ADDR_TYPE_IP6:
449
raise ValueError, "non-IPv6 address"
450
__memcpy(self._addr.addr_data8, value, 16)
453
"""Return an addr object for our broadcast address."""
455
addr_bcast(&self._addr, &(<addr>bcast)._addr)
459
"""Return an addr object for our network address."""
461
addr_net(&self._addr, &(<addr>net)._addr)
466
memcpy(<char *>&(<addr>a)._addr, <char *>&self._addr,
470
def __cmp__(addr x, addr y):
471
return addr_cmp(&x._addr, &y._addr)
473
def __contains__(self, addr other):
474
cdef addr_t s1, s2, o1, o2
475
if addr_net(&self._addr, &s1) != 0 or \
476
addr_bcast(&self._addr, &s2) != 0 or \
477
addr_net(&other._addr, &o1) != 0 or \
478
addr_bcast(&other._addr, &o2) != 0:
480
return addr_cmp(&o1, &s1) >= 0 and addr_cmp(&o2, &s2) <= 0
484
p = addr_ntoa(&self._addr)
486
return '<invalid address>'
493
cdef struct arp_entry:
496
ctypedef struct arp_t:
498
ctypedef int (*arp_handler)(arp_entry *entry, void *arg)
501
int arp_add(arp_t *arp, arp_entry *entry)
502
int arp_delete(arp_t *arp, arp_entry *entry)
503
int arp_get(arp_t *arp, arp_entry *entry)
504
int arp_loop(arp_t *arp, arp_handler callback, void *arg)
505
arp_t *arp_close(arp_t *arp)
507
void __arp_pack_hdr_ethip "arp_pack_hdr_ethip" (char *buf,
508
int op, eth_addr_t sha, ip_addr_t spa,
509
eth_addr_t dha, ip_addr_t dpa)
511
ARP_HDR_LEN = 8 # /* base ARP header length */
512
ARP_ETHIP_LEN = 20 # /* base ARP message length */
514
ARP_HRD_ETH = 0x0001 # /* ethernet hardware */
515
ARP_HRD_IEEE802=0x0006 # /* IEEE 802 hardware */
517
ARP_PRO_IP = 0x0800 # /* IP protocol */
519
ARP_OP_REQUEST = 1 # /* request to resolve ha given pa */
520
ARP_OP_REPLY = 2 # /* response giving hardware address */
521
ARP_OP_REVREQUEST = 3 # /* request to resolve pa given ha */
522
ARP_OP_REVREPLY = 4 # /* response giving protocol address */
524
cdef int __arp_callback(arp_entry *entry, void *arg):
526
ret = f(addr(addr_ntoa(&entry.arp_pa)), addr(addr_ntoa(&entry.arp_ha)), a)
532
"""arp() -> ARP table object
534
Open a handle to the system ARP table.
539
self.arp = arp_open()
541
raise OSError, __oserror()
543
def add(self, addr pa, addr ha):
544
"""Add an entry to the system ARP table.
547
pa -- ADDR_TYPE_IP network address object
548
ha -- ADDR_TYPE_ETH network address object
551
entry.arp_pa = pa._addr
552
entry.arp_ha = ha._addr
553
if arp_add(self.arp, &entry) < 0:
554
raise OSError, __oserror()
556
def delete(self, addr pa):
557
"""Delete an entry from the system ARP table.
560
pa -- ADDR_TYPE_IP network address object
563
entry.arp_pa = pa._addr
564
if arp_delete(self.arp, &entry) < 0:
565
raise OSError, __oserror()
567
def get(self, addr pa):
568
"""Return the hardware address for a given protocol address
569
in the system ARP table.
572
pa -- ADDR_TYPE_IP network address object
575
entry.arp_pa = pa._addr
576
if arp_get(self.arp, &entry) == 0:
577
return addr(addr_ntoa(&entry.arp_ha))
580
def loop(self, callback, arg=None):
581
"""Iterate over the system ARP table, invoking a user callback
582
with each entry, returning the status of the callback routine.
585
callback -- callback function with (pa, ha, arg) prototype.
586
If this function returns a non-zero value, the loop
588
arg -- optional callback argument
590
_arg = (callback, arg)
591
return arp_loop(self.arp, __arp_callback, <void *>_arg)
596
def arp_pack_hdr_ethip(op=ARP_OP_REQUEST,
597
sha=ETH_ADDR_UNSPEC, spa=IP_ADDR_ANY,
598
dha=ETH_ADDR_UNSPEC, dpa=IP_ADDR_ANY):
599
"""Return a packed binary string representing an Ethernet/IP ARP message.
602
op -- operation (ARP_OP_*) (16-bit integer)
603
sha -- sender Ethernet address (6-byte binary string)
604
spa -- sender IP address (4-byte binary string)
605
dha -- destination Ethernet address (6-byte binary string)
606
dpa -- destination IP address (4-byte binary string)
609
cdef eth_addr_t sh, dh
610
cdef ip_addr_t sp, dp
611
__memcpy(sh.data, sha, 6)
612
__memcpy(dh.data, dha, 6)
613
__memcpy(<char *>&sp, spa, 4)
614
__memcpy(<char *>&dp, dpa, 4)
615
__arp_pack_hdr_ethip(buf, op, sh, sp, dh, dp)
616
return PyString_FromStringAndSize(buf, 28)
622
void __icmp_pack_hdr "icmp_pack_hdr" (char *hdr, int type, int code)
624
def icmp_pack_hdr(type, code):
625
"""Return a packed binary string representing an ICMP header.
628
type -- ICMP type (8-bit integer)
629
code -- ICMP code (8-bit integer)
632
__icmp_pack_hdr(buf, type, code)
633
return PyString_FromStringAndSize(buf, sizeof(buf))
639
void __tcp_pack_hdr "tcp_pack_hdr" (char *hdr,
640
int sport, int dport, unsigned long seq, unsigned long ack, int flags, int win, int urp)
642
TCP_HDR_LEN = 20 # /* base TCP header length */
644
TH_FIN = 0x01 # /* end of data */
645
TH_SYN = 0x02 # /* synchronize sequence numbers */
646
TH_RST = 0x04 # /* reset connection */
647
TH_PUSH = 0x08 # /* push */
648
TH_ACK = 0x10 # /* acknowledgement number set */
649
TH_URG = 0x20 # /* urgent pointer set */
650
TH_ECE = 0x40 # /* ECN echo, RFC 3168 */
651
TH_CWR = 0x80 # /* congestion window reduced */
653
TCP_PORT_MAX = 65535 # /* maximum port */
654
TCP_WIN_MAX = 65535 # /* maximum (unscaled) window */
656
def tcp_pack_hdr(sport, dport, seq=1, ack=0, flags=TH_SYN,
657
win=TCP_WIN_MAX, urp=0):
658
"""Return a packed binary string representing a TCP header.
661
sport -- source port (16-bit integer)
662
dport -- destination port (16-bit integer)
663
seq -- sequence number (32-bit integer)
664
ack -- acknowledgment number (32-bit integer)
665
flags -- control flags (TH_*) (8-bit integer bitmask)
666
win -- window size (16-bit integer)
667
urp -- urgent pointer (16-bit integer)
670
__tcp_pack_hdr(buf, sport, dport, seq, ack, flags, win, urp)
671
return PyString_FromStringAndSize(buf, sizeof(buf))
677
void __udp_pack_hdr "udp_pack_hdr" (char *hdr, int sport, int dport, int ulen)
682
def udp_pack_hdr(sport, dport, ulen=UDP_HDR_LEN):
683
"""Return a packed binary string representing a UDP header.
686
sport -- source port (16-bit integer)
687
dport -- destination port (16-bit integer)
688
ulen -- UDP header + data length (16-bit integer)
691
__udp_pack_hdr(buf, sport, dport, ulen)
692
return PyString_FromStringAndSize(buf, sizeof(buf))
699
unsigned int intf_len
701
unsigned short intf_type
702
unsigned short intf_flags
703
unsigned int intf_mtu
706
addr_t intf_link_addr
707
unsigned int intf_alias_num
708
addr_t intf_alias_addrs[8] # XXX
709
ctypedef struct intf_t:
711
ctypedef int (*intf_handler)(intf_entry *entry, void *arg)
714
int intf_get(intf_t *intf, intf_entry *entry)
715
int intf_get_src(intf_t *intf, intf_entry *entry, addr_t *src)
716
int intf_get_dst(intf_t *intf, intf_entry *entry, addr_t *dst)
717
int intf_set(intf_t *intf, intf_entry *entry)
718
int intf_loop(intf_t *intf, intf_handler callback, void *arg)
719
intf_t *intf_close(intf_t *intf)
721
INTF_TYPE_OTHER = 1 # /* other */
722
INTF_TYPE_ETH = 6 # /* Ethernet */
723
INTF_TYPE_LOOPBACK = 24 # /* software loopback */
724
INTF_TYPE_TUN = 53 # /* proprietary virtual/internal */
726
INTF_FLAG_UP = 0x01 # /* enable interface */
727
INTF_FLAG_LOOPBACK = 0x02 # /* is a loopback net (r/o) */
728
INTF_FLAG_POINTOPOINT = 0x04 # /* point-to-point link (r/o) */
729
INTF_FLAG_NOARP = 0x08 # /* disable ARP */
730
INTF_FLAG_BROADCAST = 0x10 # /* supports broadcast (r/o) */
731
INTF_FLAG_MULTICAST = 0x20 # /* supports multicast (r/o) */
733
cdef object ifent_to_dict(intf_entry *entry):
735
d['name'] = entry.intf_name
736
d['type'] = entry.intf_type
737
d['flags'] = entry.intf_flags
738
d['mtu'] = entry.intf_mtu
739
if entry.intf_addr.addr_type != ADDR_TYPE_NONE:
740
d['addr'] = addr(addr_ntoa(&entry.intf_addr))
741
if entry.intf_dst_addr.addr_type != ADDR_TYPE_NONE:
742
d['dst_addr'] = addr(addr_ntoa(&entry.intf_dst_addr))
743
if entry.intf_link_addr.addr_type != ADDR_TYPE_NONE:
744
d['link_addr'] = addr(addr_ntoa(&entry.intf_link_addr))
745
if entry.intf_alias_num > 0:
747
for i from 0 <= i < entry.intf_alias_num:
748
l.append(addr(addr_ntoa(&entry.intf_alias_addrs[i])))
752
cdef dict_to_ifent(object d, intf_entry *entry):
754
strlcpy(entry.intf_name, s, 16)
756
entry.intf_flags = d['flags']
758
entry.intf_mtu = d['mtu']
760
entry.intf_addr = (<addr>d['addr'])._addr
762
entry.intf_dst_addr = (<addr>d['dst_addr'])._addr
764
entry.intf_link_addr = (<addr>d['link_addr'])._addr
765
if 'alias_addrs' in d:
766
entry.intf_alias_num = len(d['alias_addrs'])
767
for i from 0 <= i < entry.intf_alias_num:
768
entry.intf_alias_addrs[i] = (<addr>d['alias_addrs'][i])._addr
770
cdef int __intf_callback(intf_entry *entry, void *arg):
772
ret = f(ifent_to_dict(entry), a)
778
"""intf() -> Interface table object
780
Open a handle to the system network interface table.
785
self.intf = intf_open()
787
raise OSError, __oserror()
790
"""Return the configuration for a network interface as a dict.
792
cdef intf_entry *ifent
794
ifent = <intf_entry *>buf
795
ifent.intf_len = 1024
796
strlcpy(ifent.intf_name, name, 16)
797
if intf_get(self.intf, ifent) < 0:
798
raise OSError, __oserror()
799
return ifent_to_dict(ifent)
801
def get_src(self, addr src):
802
"""Return the configuration for the interface whose primary address
803
matches the specified source address.
805
cdef intf_entry *ifent
807
ifent = <intf_entry *>buf
808
ifent.intf_len = 1024
809
if intf_get_src(self.intf, ifent, &src._addr) < 0:
810
raise OSError, __oserror()
811
return ifent_to_dict(ifent)
813
def get_dst(self, addr dst):
814
"""Return the configuration for the best interface with which to
815
reach the specified dst address.
817
cdef intf_entry *ifent
819
ifent = <intf_entry *>buf
820
ifent.intf_len = 1024
821
if intf_get_dst(self.intf, ifent, &dst._addr) < 0:
822
raise OSError, __oserror()
823
return ifent_to_dict(ifent)
826
"""Set the configuration for an interface from a dict.
829
name -- name of interface to set (string)
830
flags -- interface flags (INTF_FLAG_*) (integer bitmask)
831
mtu -- interface MTU (integer)
832
addr -- primary network address (addr object)
833
dst_addr -- point-to-point dst address (addr object)
834
link_addr -- link-layer address (addr object)
835
alias_addrs -- additional network addresses (list of addr objects)
837
cdef intf_entry *ifent
839
memset(buf, 0, sizeof(buf))
840
ifent = <intf_entry *>buf
841
ifent.intf_len = 1024
842
dict_to_ifent(d, ifent)
843
if intf_set(self.intf, ifent) < 0:
844
raise OSError, __oserror()
846
def loop(self, callback, arg=None):
847
"""Iterate over the system interface table, invoking a user callback
848
with each entry, returning the status of the callback routine.
851
callback -- callback function with (dict, arg) prototype.
852
If this function returns a non-zero value, the loop
854
arg -- optional callback argument
856
_arg = (callback, arg)
857
return intf_loop(self.intf, __intf_callback, <void *>_arg)
860
intf_close(self.intf)
866
cdef struct route_entry:
869
ctypedef struct route_t:
871
ctypedef int (*route_handler)(route_entry *entry, void *arg)
873
route_t *route_open()
874
int route_add(route_t *route, route_entry *entry)
875
int route_delete(route_t *route, route_entry *entry)
876
int route_get(route_t *route, route_entry *entry)
877
int route_loop(route_t *route, route_handler callback, void *arg)
878
route_t *route_close(route_t *route)
880
cdef int __route_callback(route_entry *entry, void *arg):
882
ret = f(addr(addr_ntoa(&entry.route_dst)),
883
addr(addr_ntoa(&entry.route_gw)), a)
889
"""route() -> Routing table object
891
Open a handle to the system routing table.
896
self.route = route_open()
898
raise OSError, __oserror()
900
def add(self, addr dst, addr gw):
901
"""Add an entry to the system routing table.
904
dst -- ADDR_TYPE_IP network address object
905
gw -- ADDR_TYPE_IP network address object
907
cdef route_entry entry
908
entry.route_dst = dst._addr
909
entry.route_gw = gw._addr
910
if route_add(self.route, &entry) < 0:
911
raise OSError, __oserror()
913
def delete(self, addr dst):
914
"""Delete an entry from the system routing table.
917
dst -- ADDR_TYPE_IP network address object
919
cdef route_entry entry
920
entry.route_dst = dst._addr
921
if route_delete(self.route, &entry) < 0:
922
raise OSError, __oserror()
924
def get(self, addr dst):
925
"""Return the hardware address for a given protocol address
926
in the system routing table.
929
dst -- ADDR_TYPE_IP network address object
931
cdef route_entry entry
932
entry.route_dst = dst._addr
933
if route_get(self.route, &entry) == 0:
934
return addr(addr_ntoa(&entry.route_gw))
937
def loop(self, callback, arg=None):
938
"""Iterate over the system routing table, invoking a user callback
939
with each entry, returning the status of the callback routine.
942
callback -- callback function with (dst, gw, arg) prototype.
943
If this function returns a non-zero value, the loop
945
arg -- optional callback argument
947
_arg = (callback, arg)
948
return route_loop(self.route, __route_callback, <void *>_arg)
951
route_close(self.route)
967
ctypedef struct fw_t:
969
ctypedef int (*fw_handler)(fw_rule *rule, void *arg)
972
int fw_add(fw_t *f, fw_rule *rule)
973
int fw_delete(fw_t *f, fw_rule *rule)
974
int fw_loop(fw_t *f, fw_handler callback, void *arg)
975
fw_t *fw_close(fw_t *f)
983
cdef object rule_to_dict(fw_rule *rule):
985
d['device'] = rule.fw_device
987
d['dir'] = rule.fw_dir
988
if rule.fw_proto != 0:
989
d['proto'] = rule.fw_proto
990
if rule.fw_src.addr_type != ADDR_TYPE_NONE:
991
d['src'] = addr(addr_ntoa(&rule.fw_src))
992
if rule.fw_dst.addr_type != ADDR_TYPE_NONE:
993
d['dst'] = addr(addr_ntoa(&rule.fw_dst))
994
if not (rule.fw_sport[0] == 0 and rule.fw_sport[1] == 0):
995
d['sport'] = [ rule.fw_sport[0], rule.fw_sport[1] ]
996
if not (rule.fw_dport[0] == 0 and rule.fw_dport[1] == 0):
997
d['dport'] = [ rule.fw_dport[0], rule.fw_dport[1] ]
1000
cdef dict_to_rule(object d, fw_rule *rule):
1002
strlcpy(rule.fw_device, s, 16)
1003
rule.fw_op = d['op']
1004
rule.fw_dir = d['dir']
1006
rule.fw_proto = d['proto']
1007
if rule.fw_proto == IP_PROTO_TCP or rule.fw_proto == IP_PROTO_UDP:
1008
rule.fw_sport[1] = 65535
1009
rule.fw_dport[1] = 65535
1011
rule.fw_src = (<addr>d['src'])._addr
1013
rule.fw_dst = (<addr>d['dst'])._addr
1015
rule.fw_sport[0] = d['sport'][0]
1016
rule.fw_sport[1] = d['sport'][1]
1018
rule.fw_dport[0] = d['dport'][0]
1019
rule.fw_dport[1] = d['dport'][1]
1021
cdef int __fw_callback(fw_rule *rule, void *arg):
1023
ret = f(rule_to_dict(rule), a)
1029
"""fw() -> Firewall ruleset object
1031
Open a handle to the local network firewall configuration.
1038
raise OSError, __oserror()
1041
"""Add a firewall rule specified as a dict.
1044
device -- interface name (string)
1045
op -- operation (FW_OP_*) (integer)
1046
dir -- direction (FW_DIR_*) (integer)
1047
proto -- IP protocol (IP_PROTO_*) (integer)
1048
src -- source address / net (addr object)
1049
dst -- destination address / net (addr object)
1050
sport -- source port range or ICMP type/mask (list of 2 integers)
1051
dport -- dest port range or ICMP code/mask (list of 2 integers)
1054
memset(<char *>&rule, 0, sizeof(rule))
1055
dict_to_rule(d, &rule)
1056
if fw_add(self.fw, &rule) < 0:
1057
raise OSError, __oserror()
1059
def delete(self, d):
1060
"""Delete a firewall rule specified as a dict."""
1062
memset(<char *>&rule, 0, sizeof(rule))
1063
dict_to_rule(d, &rule)
1064
if fw_delete(self.fw, &rule) < 0:
1065
raise OSError, __oserror()
1067
def loop(self, callback, arg=None):
1068
"""Iterate over the local firewall ruleset, invoking a user callback
1069
with each entry, returning the status of the callback routine.
1072
callback -- callback function with (dict, arg) prototype.
1073
If this function returns a non-zero value, the loop
1075
arg -- optional callback argument
1077
_arg = (callback, arg)
1078
return fw_loop(self.fw, __fw_callback, <void *>_arg)
1087
ctypedef struct rand_t:
1091
int rand_get(rand_t *rand, char *buf, int len)
1092
int rand_set(rand_t *rand, char *seed, int len)
1093
int rand_add(rand_t *rand, char *buf, int len)
1094
unsigned int rand_uint8(rand_t *rand)
1095
unsigned int rand_uint16(rand_t *rand)
1096
unsigned long rand_uint32(rand_t *rand)
1097
rand_t *rand_close(rand_t *rand)
1100
"""rand() -> Pseudo-random number generator
1102
Obtain a handle for fast, cryptographically strong pseudo-random
1103
number generation. The starting seed is derived from the system
1104
random data source device (if one exists), or from the current time
1105
and random stack contents.
1110
self.rand = rand_open()
1112
raise OSError, __oserror()
1115
"""Return a string of random bytes.
1118
len -- number of random bytes to generate
1121
rand_get(self.rand, buf, len)
1125
"""Initialize the PRNG from a known seed.
1128
string -- binary string seed value
1130
rand_set(self.rand, buf, PyString_Size(buf))
1133
"""Add additional entropy into the PRNG mix.
1136
string -- binary string
1138
rand_add(self.rand, buf, PyString_Size(buf))
1141
"""Return a random 8-bit integer."""
1142
return rand_uint8(self.rand)
1145
"""Return a random 16-bit integer."""
1146
return rand_uint16(self.rand)
1149
"""Return a random 32-bit integer."""
1150
return rand_uint32(self.rand)