1 ====================
2 Your First Packets
3 ====================
4
5 Introduction
6 ============
7
8 This tutorial is meant for everybody who wants to start using UMPA.
9 You will learn how to build and send your packets.
10
11 Examples
12 --------
13
14 Check examples/* directory for already written full code examples.
15
16 They are also available on http://trac.umitproject.org/browser/branch/UMPA/examples/
17
18 ..2, 3...GO!
19 ============
20
21 import UMPA
22 -----------
23
24 Ok, at the beginning we need to import UMPA.
25
26 .. code-block:: python
27
28 In r1: import umit.umpa
29 In r2:
30
31 Pretty easy, isn't it? ;-)
32
33 After that, we have 2 classes provided: @@Packet@@ and @@Socket@@.
34 The former one is a protocol container. If you want to build new packet,
35 you have to create a Packet's object. We will use it everytime when we would
36 like to build packets.
37
38 @@Socket@@ is needed at the end of the process. We will back
39 to this point later.
40
41 security issue
42 --------------
43
44 To create RAW_SOCKET we need SUID (root priviliges), but for normal usage
45 usually it's not necessary (depends what you are doing with your application).
46
47 So, it's recommended to drop the priviliges and up them only if needed.
48 @@umit.umpa.utils@@ package provides some useful modules, and
49 the @@umit.umpa.utils.security@@ module provides functions which are usefull
50 in this case.
51
52 All we need is to import the module and call the function. Later when we need
53 to create a new socket (or to do something other what rely on SUID) we call
54 another function from the module (it will be describe later).
55
56 .. code-block:: python
57
58 In r2: import umit.umpa.utils.security
59 In r3: umit.umpa.utils.security.drop_priviliges()
60 In r4:
61
62 Please note that our process has to be run as a root. Otherwise, an excaption
63 will raise:
64
65 .. code-block:: python
66
67 In r1: import umit.umpa.utils.security
68 In r2: umit.umpa.utils.security.drop_priviliges()
69
70 Run the program with root-priviliges.
71
72 ---------------------------------------------------------------------------
73 <type 'exceptions.OSError'> Traceback (most recent call last)
74
75 /home/xsx/UMPA/<ipython console> in <module>()
76
77 /home/xsx/UMPA/umpa/utils/security.py in drop_priviliges()
78 48 nobody_id = pwd.getpwnam('nobody')r2
79 49 try:
80 ---> 50 os.seteuid(nobody_id)
81 51 except OSError:
82 52 print >> sys.stderr, "Run the program with root-priviliges.\n"
83
84 <type 'exceptions.OSError'>: [Errno 1] Operation not permitted
85
86 In r3:
87
88 protocols
89 ---------
90
91 Let's build our first packet. There are several ways to do that. We can include
92 each protocols as an arguments in @@Packet()@@ constructor, or just build
93 them independent. The second case is more interesting.
94
95 First, we need to import the @@umit.umpa.protocols@@ package. If we don't know
96 which protocols are available, we can simple check it.
97
98 .. code-block:: python
99
100 In r4: import umit.umpa.protocols
101
102 In r5: umit.umpa.protocols.get_all()
103 Outr5:
104 {'IP': <class 'umit.umpa.protocols.IP.IP'>,
105 'Payload': <class 'umit.umpa.protocols.Payload.Payload'>,
106 'TCP': <class 'umit.umpa.protocols.TCP.TCP'>,
107 'UDP': <class 'umit.umpa.protocols.UDP.UDP'>}
108
109 In r6:
110
111 There are two more functions (@@get_globals()@@ and @@get_locals()@@). We will
112 talk about them in next tutorials. But @@get_all()@@ is what you usually need.
113
114 OK, in our example we would like to build TCP/IP packet and UDP/IP.
115 Both packets with the same IP header.
116
117 IP protocol
118 -----------
119
120 .. code-block:: python
121
122 In r6: ip = umit.umpa.protocols.IP(source_address="127.0.0.1")
123
124 In r7: ip.destination_address = (67,205,14,183)
125
126 In r8: list(ip.get_fields_keys())
127 Outr8:
128 ['_version',
129 '_ihl',
130 'type_of_service',
131 '_total_length',
132 '_identification',
133 'flags',
134 '_fragment_offset',
135 'time_to_live',
136 '_protocol',
137 '_header_checksum',
138 'source_address',
139 'destination_address',
140 'options',
141 '_padding']
142
143 Ok, We've just created the IP instance. As you see, we can pass values directly
144 to constructor (@@In r6@@) or pass them later (@@In r7@@). Also, IP addresses
145 can be passed in two ways as a string or tuple (or list). To get list of
146 headers just call @@get_fields_key()@@ method. But this method is a generator,
147 so in this case we need to cast it. Names convention is pretty simple.
148 Those names are taken from the RFCs documents.
149
150 .. note::
151
152 Some fields are started with the underscrored prefix. This has a special
153 meaning. These fields may auto-generate values. So usually, we don't need
154 to care about them. But if you want to modify them - feel free to break
155 your packets ;)
156
157 TCP and Payload protocols
158 -------------------------
159
160 What next? TCP header and some payload for it..
161
162 .. code-block:: python
163
164 In r9: tcp = umit.umpa.protocols.TCP()
165
166 In r10: tcp.source_port = 2958
167
168 In r11: tcp.destination_port = 0
169
170 In r12: tcp.set_flags('control_bits', syn=True)
171
172 In r13: payload = umit.umpa.protocols.Payload()
173
174 In r14: payload.data = "this is umpa!"
175
176 In r15:
177
178 Completely simple so far, isn't it?
179
180 protocols container
181 -------------------
182
183 Ok, let's build a packet...
184
185 .. code-block:: python
186
187 In r15: first_packet = umit.umpa.Packet(ip, tcp)
188
189 In r16: first_packet.include(payload)
190
191 So, we passed 2 protocols into constructor, and included another one with the
192 @include()@ method.
193
194 Please remember that including order is important. By default, we can't break
195 the OSI model, so protocols need to be packed in the proper order. Otherwise,
196 the @@UMPAStrictException@@ will raise. If you want to break this rule, please
197 read about @@strict@@ attribute of the Packet's object in later tutorials.
198
199 print statement
200 ---------------
201
202 If we take a coffe break (longer than 5 hours) now, perhaps we will forget what
203 we built. Just print it!
204
205 .. code-block:: python
206
207 In r17: print first_packet
208 Packet contains 3 protocols
209 +-< IP >
210 | \
211 | +-[ Version ] 4 (auto - 4)
212 | +-[ IHL ] None (auto - 5)
213 | +-[ TOS ]
214 | | \
215 | | -{ precedence0 } 0
216 | | -{ precedence1 } 0
217 | | -{ precedence2 } 0
218 | | -{ delay } 0
219 | | -{ throughput } 0
220 | | -{ relibility } 0
221 | | -{ reserved0 } 0
222 | | -{ reserved1 } 0
223 | | /
224 | \-[ TOS ] contains 8 bit flags
225 | +-[ Total Length ] None (auto - 0)
226 | +-[ Identification ] 0 (auto - 0)
227 | +-[ Flags ]
228 | | \
229 | | -{ reserved } 0
230 | | -{ df } 0
231 | | -{ mf } 0
232 | | /
233 | \-[ Flags ] contains 3 bit flags
234 | +-[ Fragment Offset ] 0 (auto - 0)
235 | +-[ TTL ] 64 (auto - 64)
236 | +-[ Protocol ] None (auto - 0)
237 | +-[ _Header Checksum ] 0 (auto - 0)
238 | +-[ Source Address ] 127.0.0.1
239 | +-[ Destination Address ] (67, 205, 14, 183)
240 | +-[ Options ]
241 | | \
242 | | /
243 | \-[ Options ] contains 0 bit flags
244 | +-[ Padding ] 0 (auto - 0)
245 \-< IP > contains 14 fields
246 <umit.umpa.protocols.IP.IP object at 0xb78c2a4c>
247 +-< TCP >
248 | \
249 | +-[ Source Port ] 2958
250 | +-[ Destination Port ] 0
251 | +-[ Sequence Number ] None (auto - 0)
252 | +-[ Acknowledgment Number ] None (auto - 1)
253 | +-[ [[DataOffset]] ] None (auto - 5)
254 | +-[ Reserved ] 0 (auto - 0)
255 | +-[ Control Bits ]
256 | | \
257 | | -{ urg } 0
258 | | -{ ack } 0
259 | | -{ psh } 0
260 | | -{ rst } 0
261 | | -{ syn } 1
262 | | -{ fin } 0
263 | | /
264 | \-[ Control Bits ] contains 6 bit flags
265 | +-[ Window ] None (auto - 512)
266 | +-[ Checksum ] None (auto - 0)
267 | +-[ Urgent Pointer ] None (auto - 0)
268 | +-[ Options ]
269 | | \
270 | | /
271 | \-[ Options ] contains 0 bit flags
272 | +-[ Padding ] 0 (auto - 0)
273 \-< TCP > contains 12 fields
274 <umit.umpa.protocols.TCP.TCP object at 0xb78e774c>
275 +-< Payload >
276 | \
277 | +-[ Data ] this is umpa!
278 \-< Payload > contains 1 fields
279 <umit.umpa.protocols.Payload.Payload object at 0xb78e794c>
280 <umit.umpa._packets.Packet object at 0xb78e798c>
281
282 In r18:
283
284 sockets
285 -------
286
287 Now, we are ready to send the packet!
288 To create a new socket, we will use @@umit.umpa.Socket@@ class.
289 Please remember, that we dropped our priviliges so we need to get them
290 back now.
291
292 We can do it in 2 ways.
293 1. atomic way (*recommended*)
294
295 .. code-block:: python
296
297 In r18: sock = umit.umpa.utils.security.super_priviliges(umit.umpa.Socket)
298
299 In r19:
300
301 2. normal way
302
303 .. code-block:: python
304
305 In r18: umit.umpa.utils.security.drop_priviliges()
306
307 In r19: umit.umpa.utils.security.super_priviliges()
308
309 In r20: sock = umit.umpa.Socket()
310
311 In r21: umit.umpa.utils.security.drop_priviliges()
312
313 In r22:
314
315 Both are correct. But the former is recommended. How does it work?
316
317 We pass arguments into @@super_priviliges()@@ function, the first has to
318 be callable, others are just arguments for the first one.
319 Result of the callable argument is returned by the @@super_priviliges()@@
320 function.
321
322 Internally in the @@super_priviliges()@@ function:
323 1. change EUID to the 0 (root)
324 2. call the first argument from passed arguments
325 3. change EUID to nobody (call @@drop_priviliges()@@)
326 4. return the result of the calling from point 2
327
328 Ok, actually we have a socket object, so let's send the packet!
329
330 .. code-block:: python
331
332 In r19: sock.send(first_packet)
333 Out r19: r53
334
335 In r20:
336
337 @@Socket.send()@@ method returns a list with sent bytes of each packets (we can
338 pass more than one packet at the same time).
339
340 UDP protocol
341 ------------
342
343 Ok, let's create another packet with a UDP header just in single line!
344
345 .. code-block:: python
346
347 In r20: udp = umit.umpa.protocols.UDP(source_port=0, destination_port=7)
348
349 In r21:
350
351 ttl aka enumfield
352 -----------------
353
354 Now, we can simple create a new packet and use already created @@sock@@ object
355 to send it out, but before we will do that, lets change TTL field of
356 the IP protocol.
357
358 Some common fields like TTL or ports in TCP/UDP headers are @@EnumField@@
359 objects. What does it mean? Well, this is a simple numeric field but with
360 special behaviour.
361 We can pass common names instead of numbers (what is easier to remember).
362 Let's do it on the TTL example.
363
364 .. code-block:: python
365
366 In r21: ip.get_field("time_to_live").enumerable
367 Outr21:
368 {'aix': 60,
369 'dec': 30,
370 'freebsd': 64,
371 'irix': 60,
372 'linux': 64,
373 'macos': 60,
374 'os2': 64,
375 'solaris': 255,
376 'sunos': 60,
377 'ultrix': 60,
378 'windows': 128}
379
380 In r22: ip.time_to_live = "windows"
381
382 In r23:
383
384 Why can't we use @@ip.time_to_live.enumerable@@ in the first line?
385 Well, attributes like object._name_of_field_ are reserved only to get/set
386 values of them. They handle only with values. To get a reference to the field's
387 object we need to use @@get_field()@@ method.
388
389 print statement is sooo cool
390 ----------------------------
391
392 Don't forget about checking if everything is correct :-)
393
394 .. code-block:: python
395
396 In r23: print second_packet
397 Packet contains 2 protocols
398 +-< IP >
399 | \
400 | +-[ Version ] 4 (auto - 4)
401 | +-[ IHL ] None (auto - 5)
402 | +-[ TOS ]
403 | | \
404 | | -{ precedence0 } 0
405 | | -{ precedence1 } 0
406 | | -{ precedence2 } 0
407 | | -{ delay } 0
408 | | -{ throughput } 0
409 | | -{ relibility } 0
410 | | -{ reserved0 } 0
411 | | -{ reserved1 } 0
412 | | /
413 | \-[ TOS ] contains 8 bit flags
414 | +-[ Total Length ] None (auto - 28)
415 | +-[ Identification ] 0 (auto - 0)
416 | +-[ Flags ]
417 | | \
418 | | -{ reserved } 0
419 | | -{ df } 0
420 | | -{ mf } 0
421 | | /
422 | \-[ Flags ] contains 3 bit flags
423 | +-[ Fragment Offset ] 0 (auto - 0)
424 | +-[ TTL ] 128 (auto - 128)
425 | +-[ Protocol ] None (auto - 17)
426 | +-[ _Header Checksum ] 0 (auto - 0)
427 | +-[ Source Address ] 127.0.0.1
428 | +-[ Destination Address ] (67, 205, 14, 183)
429 | +-[ Options ]
430 | | \
431 | | /
432 | \-[ Options ] contains 0 bit flags
433 | +-[ Padding ] 0 (auto - 0)
434 \-< IP > contains 14 fields
435 <umit.umpa.protocols.IP.IP object at 0xb78c8b6c>
436 +-< UDP >
437 | \
438 | +-[ Source Port ] 0
439 | +-[ Destination Port ] 7
440 | +-[ Length ] None (auto - 8)
441 | +-[ Checksum ] None (auto - 0)
442 \-< UDP > contains 4 fields
443 <umit.umpa.protocols.UDP.UDP object at 0xb78c8b0c>
444 <umit.umpa._packets.Packet object at 0xb78c8ecc>
445
446 In r24:
447
448 As you see, TTL is "in Windows mode".
449
450 packing and sending again
451 -------------------------
452
453 .. code-block:: python
454
455 In r24: second_packet = umit.umpa.Packet(ip, udp)
456
457 In r25: sock.send(first_packet, second_packet)
458 Out r25: [53, 28]
459
460 In r26:
461
462 We sent 2 packets. 53 bytes first for the first packet and 28 for the second.
463
464 Now, just make some exercises to get more practice!