UMPADocumentationTutorialsYourFirstPackets

Version 5 (Bartosz SKOWRON -, 08/28/2008 04:15 pm)

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