ethernet.py 2.17 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import fcntl
import socket
import struct
import sys
import random

ETH_P_ALL = 0x0003
SIOCGIFHWADDR = 0x8927       # Get hardware address

def parse_address(addr):
    return struct.pack('!6B', *list(int(v, 16) for v in addr.split(':')))
                       
class ETH(object):

    def __init__(self, name, send_loss=0.0, recv_loss=0.0):
        self.name = name
        self.send_loss = send_loss
        self.recv_loss = recv_loss
        self.socket = socket.socket(socket.AF_PACKET,
                                    socket.SOCK_RAW,
                                    socket.htons(ETH_P_ALL))
        self.socket.bind((name, 0x0000))
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 100000)
        ifs = fcntl.ioctl(self.socket, SIOCGIFHWADDR,
                          struct.pack("16sH14s",
                                      self.name.encode(),
                                      0, "".encode()))
        self.macaddr = struct.unpack("16x2x14s", ifs)[0][0:6]
        
    def send(self, data):
        u = random.uniform(0, 1.0)
        if u >= self.send_loss:
            data = data[0:6] + self.macaddr + data[12:]
            self.socket.send(data)
        else:
            logger.log('Dropped sent packet')

    def recv(self, maxlength):
        def hexdump(data):
            pos = 0
            while len(data):
                hex = ' '.join(map(lambda c: '%02.2x' % ord(c), data[0:16]))
                ascii = ''.join(map(lambda c: '%c' %
                                    (c > ' ' and c <= '\x7f' and c or '.'),
                                     data[0:16]))
                print '%04x: %-50s%s' % (pos, hex, ascii)
                data = data[16:]
                pos += 16
        while True:
            result = self.socket.recv(maxlength)
            #hexdump(result)
            u = random.uniform(0, 1.0)
            if u >= self.send_loss:
                return result
            else:
                logger.log('Dropped received packet')

    def __repr__(self):
        def mac_to_str(mac):
            return ":".join(["%02x" % b for b in self.macaddr])
                
        return "ETH(%s, %s)" % (self.name, mac_to_str(self.macaddr))