aboutsummaryrefslogtreecommitdiffstats
path: root/node-admin/scripts/pyroute2/protocols/__init__.py
blob: 25cf566af488a731f96b0664869b024a287dcef4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# By Peter V. Saveliev https://pypi.python.org/pypi/pyroute2. Dual licensed under the Apache 2 and GPLv2+ see https://github.com/svinota/pyroute2 for License details.
import struct
from socket import inet_ntop
from socket import inet_pton
from socket import AF_INET
from pyroute2.common import basestring

#
# IEEE = 802.3 Ethernet magic constants. The frame sizes omit
# the preamble and FCS/CRC (frame check sequence).
#

ETH_ALEN = 6  # Octets in one ethernet addr
ETH_HLEN = 14  # Total octets in header.
ETH_ZLEN = 60  # Min. octets in frame sans FCS
ETH_DATA_LEN = 1500  # Max. octets in payload
ETH_FRAME_LEN = 1514  # Max. octets in frame sans FCS
ETH_FCS_LEN = 4  # Octets in the FCS

#
# These are the defined Ethernet Protocol ID's.
#

ETH_P_LOOP = 0x0060  # Ethernet Loopback packet
ETH_P_PUP = 0x0200  # Xerox PUP packet
ETH_P_PUPAT = 0x0201  # Xerox PUP Addr Trans packet
ETH_P_IP = 0x0800  # Internet Protocol packet
ETH_P_X25 = 0x0805  # CCITT X.25
ETH_P_ARP = 0x0806  # Address Resolution packet
ETH_P_BPQ = 0x08FF  # G8BPQ AX.25 Ethernet Packet
# ^^^ [ NOT AN OFFICIALLY REGISTERED ID ]
ETH_P_IEEEPUP = 0x0a00  # Xerox IEEE802.3 PUP packet
ETH_P_IEEEPUPAT = 0x0a01  # Xerox IEEE802.3 PUP Addr Trans packet
ETH_P_DEC = 0x6000  # DEC Assigned proto
ETH_P_DNA_DL = 0x6001  # DEC DNA Dump/Load
ETH_P_DNA_RC = 0x6002  # DEC DNA Remote Console
ETH_P_DNA_RT = 0x6003  # DEC DNA Routing
ETH_P_LAT = 0x6004  # DEC LAT
ETH_P_DIAG = 0x6005  # DEC Diagnostics
ETH_P_CUST = 0x6006  # DEC Customer use
ETH_P_SCA = 0x6007  # DEC Systems Comms Arch
ETH_P_TEB = 0x6558  # Trans Ether Bridging
ETH_P_RARP = 0x8035  # Reverse Addr Res packet
ETH_P_ATALK = 0x809B  # Appletalk DDP
ETH_P_AARP = 0x80F3  # Appletalk AARP
ETH_P_8021Q = 0x8100  # = 802.1Q VLAN Extended Header
ETH_P_IPX = 0x8137  # IPX over DIX
ETH_P_IPV6 = 0x86DD  # IPv6 over bluebook
ETH_P_PAUSE = 0x8808  # IEEE Pause frames. See = 802.3 = 31B
ETH_P_SLOW = 0x8809  # Slow Protocol. See = 802.3ad = 43B
ETH_P_WCCP = 0x883E  # Web-cache coordination protocol
# defined in draft-wilson-wrec-wccp-v2-00.txt
ETH_P_PPP_DISC = 0x8863  # PPPoE discovery messages
ETH_P_PPP_SES = 0x8864  # PPPoE session messages
ETH_P_MPLS_UC = 0x8847  # MPLS Unicast traffic
ETH_P_MPLS_MC = 0x8848  # MPLS Multicast traffic
ETH_P_ATMMPOA = 0x884c  # MultiProtocol Over ATM
ETH_P_LINK_CTL = 0x886c  # HPNA, wlan link local tunnel
ETH_P_ATMFATE = 0x8884  # Frame-based ATM Transport over Ethernet

ETH_P_PAE = 0x888E  # Port Access Entity (IEEE = 802.1X)
ETH_P_AOE = 0x88A2  # ATA over Ethernet
ETH_P_8021AD = 0x88A8  # = 802.1ad Service VLAN
ETH_P_802_EX1 = 0x88B5  # = 802.1 Local Experimental = 1.
ETH_P_TIPC = 0x88CA  # TIPC
ETH_P_8021AH = 0x88E7  # = 802.1ah Backbone Service Tag
ETH_P_1588 = 0x88F7  # IEEE = 1588 Timesync
ETH_P_FCOE = 0x8906  # Fibre Channel over Ethernet
ETH_P_TDLS = 0x890D  # TDLS
ETH_P_FIP = 0x8914  # FCoE Initialization Protocol
ETH_P_QINQ1 = 0x9100  # deprecated QinQ VLAN
# ^^^ [ NOT AN OFFICIALLY REGISTERED ID ]
ETH_P_QINQ2 = 0x9200  # deprecated QinQ VLAN
# ^^^ [ NOT AN OFFICIALLY REGISTERED ID ]
ETH_P_QINQ3 = 0x9300  # deprecated QinQ VLAN
# ^^^ [ NOT AN OFFICIALLY REGISTERED ID ]
ETH_P_EDSA = 0xDADA  # Ethertype DSA
# ^^^ [ NOT AN OFFICIALLY REGISTERED ID ]
ETH_P_AF_IUCV = 0xFBFB  # IBM af_iucv
# ^^^ [ NOT AN OFFICIALLY REGISTERED ID ]

#
# Non DIX types. Won't clash for = 1500 types.
#

ETH_P_802_3 = 0x0001  # Dummy type for = 802.3 frames
ETH_P_AX25 = 0x0002  # Dummy protocol id for AX.25
ETH_P_ALL = 0x0003  # Every packet (be careful!!!)
ETH_P_802_2 = 0x0004  # = 802.2 frames
ETH_P_SNAP = 0x0005  # Internal only
ETH_P_DDCMP = 0x0006  # DEC DDCMP: Internal only
ETH_P_WAN_PPP = 0x0007  # Dummy type for WAN PPP frames*/
ETH_P_PPP_MP = 0x0008  # Dummy type for PPP MP frames
ETH_P_LOCALTALK = 0x0009  # Localtalk pseudo type
ETH_P_CAN = 0x000C  # Controller Area Network
ETH_P_PPPTALK = 0x0010  # Dummy type for Atalk over PPP*/
ETH_P_TR_802_2 = 0x0011  # = 802.2 frames
ETH_P_MOBITEX = 0x0015  # Mobitex (kaz@cafe.net)
ETH_P_CONTROL = 0x0016  # Card specific control frames
ETH_P_IRDA = 0x0017  # Linux-IrDA
ETH_P_ECONET = 0x0018  # Acorn Econet
ETH_P_HDLC = 0x0019  # HDLC frames
ETH_P_ARCNET = 0x001A  # = 1A for ArcNet :-)
ETH_P_DSA = 0x001B  # Distributed Switch Arch.
ETH_P_TRAILER = 0x001C  # Trailer switch tagging
ETH_P_PHONET = 0x00F5  # Nokia Phonet frames
ETH_P_IEEE802154 = 0x00F6  # IEEE802.15.4 frame
ETH_P_CAIF = 0x00F7  # ST-Ericsson CAIF protocol


class msg(dict):
    buf = None
    data_len = None
    fields = ()
    _fields_names = ()
    types = {'uint8': 'B',
             'uint16': 'H',
             'uint32': 'I',
             'be16': '>H',
             'ip4addr': {'format': '4s',
                         'decode': lambda x: inet_ntop(AF_INET, x),
                         'encode': lambda x: [inet_pton(AF_INET, x)]},
             'l2addr': {'format': '6B',
                        'decode': lambda x: ':'.join(['%x' % i for i in x]),
                        'encode': lambda x: [int(i, 16) for i in
                                             x.split(':')]},
             'l2paddr': {'format': '6B10s',
                         'decode': lambda x: ':'.join(['%x' % i for i in
                                                       x[:6]]),
                         'encode': lambda x: [int(i, 16) for i in
                                              x.split(':')] + [10 * b'\x00']}}

    def __init__(self, content=None, buf=b'', offset=0, value=None):
        content = content or {}
        dict.__init__(self, content)
        self.buf = buf
        self.offset = offset
        self.value = value
        self._register_fields()

    def _register_fields(self):
        self._fields_names = tuple([x[0] for x in self.fields])

    def _get_routine(self, mode, fmt):
        fmt = self.types.get(fmt, fmt)
        if isinstance(fmt, dict):
            return (fmt['format'],
                    fmt.get(mode, lambda x: x))
        else:
            return (fmt, lambda x: x)

    def reset(self):
        self.buf = b''

    def decode(self):
        self._register_fields()
        for field in self.fields:
            name, sfmt = field[:2]
            fmt, routine = self._get_routine('decode', sfmt)
            size = struct.calcsize(fmt)
            value = struct.unpack(fmt, self.buf[self.offset:
                                                self.offset + size])
            if len(value) == 1:
                value = value[0]
            if isinstance(value, basestring) and sfmt[-1] == 's':
                value = value[:value.find(b'\x00')]
            self[name] = routine(value)
            self.offset += size
        return self

    def encode(self):
        self._register_fields()
        for field in self.fields:
            name, fmt = field[:2]
            default = b'\x00' if len(field) <= 2 else field[2]
            fmt, routine = self._get_routine('encode', fmt)
            # special case: string
            if fmt == 'string':
                self.buf += routine(self[name])[0]
            else:
                size = struct.calcsize(fmt)
                if self[name] is None:
                    if not isinstance(default, basestring):
                        self.buf += struct.pack(fmt, default)
                    else:
                        self.buf += default * (size // len(default))
                else:
                    value = routine(self[name])
                    if not isinstance(value, (set, tuple, list)):
                        value = [value]
                    self.buf += struct.pack(fmt, *value)
        return self

    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            if key in self._fields_names:
                return None
            raise


class ethmsg(msg):
    fields = (('dst', 'l2addr'),
              ('src', 'l2addr'),
              ('type', 'be16'))


class ip4msg(msg):
    fields = (('verlen', 'uint8', 0x45),
              ('dsf', 'uint8'),
              ('len', 'be16'),
              ('id', 'be16'),
              ('flags', 'uint16'),
              ('ttl', 'uint8', 128),
              ('proto', 'uint8'),
              ('csum', 'be16'),
              ('src', 'ip4addr'),
              ('dst', 'ip4addr'))


class udp4_pseudo_header(msg):
    fields = (('src', 'ip4addr'),
              ('dst', 'ip4addr'),
              ('pad', 'uint8'),
              ('proto', 'uint8', 17),
              ('len', 'be16'))


class udpmsg(msg):
    fields = (('sport', 'be16'),
              ('dport', 'be16'),
              ('len', 'be16'),
              ('csum', 'be16'))