
|
Packet Purgatory Tutorial
Part 2: Using a Proxy IP to Capture Packets Return to Part 1 The program we wrote in the first part of this tutorial used the default settings for everything. In a lot of cases, the defaults are good enough, but sometimes they're not. This section of the tutorial will discuss when the defaults won't work for you, and what you need to do in order to change them. By default, Packet Purgatory does some deep surgery in order to do what it does. It changes the route tables to point out the loopback, modifies firewall rules to block inbound traffic, and puts the interface into promiscuous mode. This can break in a number of situations:
Using proxy IP capture, an unused IP address on the local subnet is used to proxy communication. Packet Purgatory will handle ARPing for that IP address, so packets destined to it will be properly received by the network card. In order to enable proxy IP capture, a few changes must be made to the sample program. The first that we must do is to modify the type of packet capture that Packet Purgatory will run. We can do this with the packetp_set_type() function: int packetp_set_type(struct packetp_ctx *ctx, int type);The context is the same context we've been using before, the type is one of PP_FAKEIP, or PP_LOOPFW, both defined in packetp.h. By default, PP_LOOPFW is used. In the future, there may be additional types added to Packet Purgatory. For right now, add the following line above packetp_start(): packetp_set_type(pp_ctx, PP_FAKEIP);In addition to setting changing the type of capture method Packet Purgatory will use, we need to provide some additional information, adding it into the context. We must add in the proxy IP address, which must be an address on the local subnet, using the packetp_set_proxy() function. We must also set the remote IP address that we are proxying through the proxy IP address, using the packetp_set_target() function. packetp_set_proxy() is declared as follows: int packetp_set_proxy(struct packetp_ctx *ctx, struct addr *proxy);The variable ctx is the context, as always, and the variable proxy is a pointer to the addr structure containing the address of the proxy IP. (See the dnet(3) manpage for additional information regarding struct addr, it's a libdnet structure). You can use addr_aton() from dnet to fill in the struct addr packetp_set_target() has the following form: int packetp_set_target(struct packetp_ctx *ctx, struct addr *target);You know ctx by now, and the variable target contains the remote IP address that packets sent to the proxy will be relayed to after modification. Once again, use addr_aton() to fill in the struct addr. Both packetp_set_proxy() and packetp_set_target() need to be called before packetp_start(), and after packetp_init(), but other than that the order is unimportant. Let's see how this looks in actual code:
int
main(int argc, char **argv)
{
int c;
struct addr temp_addr;
struct packetp_ctx *pp_ctx
/* Initialize the Packet Purgatory context */
pp_ctx = packetp_init();
/* Retreive arguments passed in, and add the required info to the context */
while((c=getopt(argc, argv, "p:r:")) != -1) {
switch(c) {
case 'p':
addr_aton(optarg, &temp_addr);
packetp_set_proxy(pp_ctx, &temp_addr);
break;
case 'r':
addr_aton(optarg, &temp_addr);
packetp_set_target(pp_ctx, &temp_addr);
break;
}
}
packetp_set_type(pp_ctx, PP_FAKEIP);
packetp_start(pp_ctx, outbound, NULL, NULL);
return(0);
}
The outbound function can remain the same. The full code is available
here. Compile with the following:
% gcc -o pp_tut2 pp_tut2.c -lpacketp -ldnet -lpcap -pthreadLet's say this program is run with the following command line: # pp_tut2 -p 10.0.0.3 -r 192.168.0.2(This assumes that you are in the 10.0.0.0 subnet) At this point, any packets sent from your system to 10.0.0.3 will be rewritten, both to change the source address to 10.0.0.3, and the destination address to 192.168.0.2, and the TOS flag to the PREC_FLASHOVERRIDE value. Any inbound packets from 192.168.0.2 to 10.0.0.3 will be rewritten as sourced from 10.0.0.3, with a destination IP address of your machine. This mode is more restrictive, in that it can only easily carry on a conversation with one remote host at a time, but it is far more portable. For most applications, this is sufficient. So, we now know how to set up two different types of packet-rewriting schemes for Packet Purgatory. In the future, there may be additional types, (I've got my eye on the IP_MANGLE table in IPTables as a logical next step), but the inbound and outbound functions will maintain the same calling conventions, and all will be backward compatible. Next up, advanced mode! (What? There's an advanced mode? Why would you want such a thing?) Return to Part 1 Part 3: To be written... |