* changing packet length? @ 2005-05-03 21:34 BJ Premore 2005-05-06 11:14 ` Harald Welte 0 siblings, 1 reply; 8+ messages in thread From: BJ Premore @ 2005-05-03 21:34 UTC (permalink / raw) To: netfilter-devel Hi everyone. I've been pulling my hair out lately, using netfilter/ipq to try to add options to the TCP header of an outgoing packet. However, even just adding 4 bytes of no-op options results in subsequent incoming packets (via ipq_get_packet) looking mangled. (After adding the options, all appropriate fields were updated--checksums, length fields, etc. Also, I was extremely carefully to follow the specifications for adding the TCP options, proper padding, etc., etc. I'm pretty sure my problems do not have to do with the formatting of the packet.) So my hopefully simple question is, can packet sizes be changed and then reinjected using ipq_set_verdict? I found one reference that seemed to suggest that modified packets had to stay the same size. I've tested modifying packets without changing their overall byte sizes, and that does in fact seem to work (Eg, I changed the TTL field.). If the answer to the above question is 'yes', then I'll provide more details in the follow-up, in hopes of getting to the bottom of my troubles. Thanks in advance, -bj BJ Premore ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: changing packet length? 2005-05-03 21:34 changing packet length? BJ Premore @ 2005-05-06 11:14 ` Harald Welte 2005-05-06 14:11 ` BJ Premore 2005-05-12 15:25 ` Todd Underwood 0 siblings, 2 replies; 8+ messages in thread From: Harald Welte @ 2005-05-06 11:14 UTC (permalink / raw) To: BJ Premore; +Cc: netfilter-devel [-- Attachment #1: Type: text/plain, Size: 621 bytes --] On Tue, May 03, 2005 at 05:34:06PM -0400, BJ Premore wrote: > So my hopefully simple question is, can packet sizes be > changed and then reinjected using ipq_set_verdict? Of course. you just reinject the packet with a different data_len. -- - Harald Welte <laforge@netfilter.org> http://netfilter.org/ ============================================================================ "Fragmentation is like classful addressing -- an interesting early architectural error that shows how much experimentation was going on while IP was being designed." -- Paul Vixie [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: changing packet length? 2005-05-06 11:14 ` Harald Welte @ 2005-05-06 14:11 ` BJ Premore 2005-05-29 19:00 ` Harald Welte 2005-05-29 19:01 ` Harald Welte 2005-05-12 15:25 ` Todd Underwood 1 sibling, 2 replies; 8+ messages in thread From: BJ Premore @ 2005-05-06 14:11 UTC (permalink / raw) To: Harald Welte, netfilter-devel Hi Harald, On Fri, May 06, 2005 at 01:14:10PM +0200, Harald Welte wrote: > On Tue, May 03, 2005 at 05:34:06PM -0400, BJ Premore wrote: > > So my hopefully simple question is, can packet sizes be > > changed and then reinjected using ipq_set_verdict? > > Of course. you just reinject the packet with a different > data_len. That's what I thought too, but I get the problems described in my original post (subsequent packets start looking mangled, basically). Have you, or has anyone, gotten this to work? I've been scouring the net for examples but in no case has any code that I've found actually changed the length of the packets before reinjecting them. I started with the sample code from the libipq man page and made incremental modifications as I worked toward my goal of adding extra options to the TCP header. Everything worked fine along the way, including changing the contents of the packet without changing its length, until I tried increasing the header by 4 bytes with four no-op TCP options. I've attached my code below. I've been using tcpdump to watch packets come and go. The TCP handshake completes, but each successive packet's payload starts accumulating extra bytes (which usually contain recognizable portions of the headers and payloads of previous packets). I'm hoping there's some silly fundamental mistake I've made that I'm overlooking, but I've been over the code so many times now that if I have made such a mistake, I'm blind to it. Thanks in advance, -BJ #include <linux/netfilter.h> #include <libipq.h> #include <stdio.h> #define BUFSIZE 65535 static void die(struct ipq_handle *h) { ipq_perror("passer"); ipq_destroy_handle(h); exit(1); } int main(int argc, char **argv) { int status; unsigned char buf[BUFSIZE]; struct ipq_handle *h; h = ipq_create_handle(0, PF_INET); if (!h) die(h); status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE); if (status < 0) die(h); // to reuse for all packets--should be plenty big enough unsigned char *pkt = malloc(10000); bzero(pkt,10000); do { bzero(&buf,BUFSIZE); status = ipq_read(h, buf, BUFSIZE, 0); if (status < 0) die(h); switch (ipq_message_type(buf)) { case NLMSG_ERROR: fprintf(stderr, "Received error message %d\n", ipq_get_msgerr(buf)); break; case IPQM_PACKET: { ipq_packet_msg_t *m = ipq_get_packet(buf); int debug = 1; fprintf(stderr, "\ngot a packet of length %d\n", m->data_len); unsigned char *pkt1 = m->payload; // ptr to start of packet fprintf(stderr, "packet destination: %d.%d.%d.%d\n", pkt1[16], pkt1[17], pkt1[18], pkt1[19]); // for now, only deal with outgoing packets to 1.2.3.4 // [IP address anonymized for posting] if (pkt1[16] != 1 || pkt1[17] != 2 || pkt1[18] != 3 || pkt1[19] != 4) { fprintf(stderr,"... skipping packet\n"); status = ipq_set_verdict(h, m->packet_id, NF_ACCEPT, 0, NULL); break; } // calculate the packet length int ipHdrLen = ((int)(pkt1[0] & 0x0f))*4; if (debug) fprintf(stderr,"IP header len: %d\n",ipHdrLen); int ipPktLen = (pkt1[2]<<8) + pkt1[3]; if (debug) fprintf(stderr,"IP packet len: %d\n",ipPktLen); int tcpHdrLen = (((int)pkt1[ipHdrLen+12])>>4)*4; if (debug) fprintf(stderr,"TCP header len: %d\n",tcpHdrLen); int tcpOptsLen = tcpHdrLen - 20; if (debug) fprintf(stderr,"TCP options len: %d\n",tcpOptsLen); int tcpDataLen = ipPktLen - (ipHdrLen+tcpHdrLen); if (debug) fprintf(stderr,"TCP data len: %d\n",tcpDataLen); int tcpDataOffset = ipHdrLen+tcpHdrLen; if (debug) fprintf(stderr,"TCP data offset: %d\n",tcpDataOffset); // print the bytes, exactly as they have been passed to us if (debug) { fprintf(stderr, "IP header:"); int i = 0; while (i<m->data_len) { if ((i%4) == 0) { fprintf(stderr, "\n "); } if ((i==ipHdrLen || i==ipHdrLen+tcpHdrLen)) { fprintf(stderr, "----------\n "); } fprintf(stderr, "%02x ", pkt1[i]); i++; } fprintf(stderr, "\n"); } // zero our local copy bzero(pkt,10000); // copy into our own, safe, reusable memory: int i = 0; for (i=0; i<ipPktLen; i++) { pkt[i] = pkt1[i]; } // // Update some of the field values in the IP & TCP headers (such // as to account for the increasing length of the packet). // // The new header length is the previous header length + 4, since // we're just adding 4 1-byte no-op options. int newTcpHdrLen = tcpHdrLen+4; if (newTcpHdrLen > 60) { fprintf(stderr,"max TCP header size exceeded (%d)",newTcpHdrLen); die(h); break; } int newIpPktLen = ipPktLen+4; m->data_len = newIpPktLen; // modify the IP packet's total length field pkt[2] = (unsigned char)((newIpPktLen>>8) & 0xff); pkt[3] = (unsigned char)(newIpPktLen & 0xff); // The first 4 bits of this next byte contains the data offset // in 4-byte words (aka the header length in bytes, divided by // 4), followed by four 0-valued reserved bits. (The value of // newTcpHdrLen is always a multiple of 4 at this point.) int newTcpHdrLenWords = (int)(newTcpHdrLen/4.0); // update it in the actual packet data pkt[ipHdrLen+12] = (unsigned char)((newTcpHdrLenWords<<4) & 0xff); // modify TCP packet as necessary: set new header field length, // add the no-ops to the options, shift the data back // shift the data to make room for the 4 no-op options in the header memmove(pkt+tcpDataOffset+4, pkt+tcpDataOffset, tcpDataLen); // // Update the TCP header. // // add the 4 no-op options pkt[ipHdrLen+tcpHdrLen] = (unsigned char)1; // option Kind = 1 pkt[ipHdrLen+tcpHdrLen+1] = (unsigned char)1; pkt[ipHdrLen+tcpHdrLen+2] = (unsigned char)1; pkt[ipHdrLen+tcpHdrLen+3] = (unsigned char)1; // BEGIN: compute the TCP checksum int total = 0; i = ipHdrLen; // the offset of the start of the TCP packet header int imax = ipHdrLen + 16; // the offset of the TCP checksum field while (i < imax) { total += ((pkt[i] << 8) | pkt[i+1]); i += 2; } // Skip existing checksum. i = ipHdrLen + 18; imax = newIpPktLen; while (i < imax) { total += ((pkt[i] << 8) | pkt[i+1]); i += 2; } // add source and dest addresses, grouped as 16-byte integers total += (pkt[12] << 8) | pkt[13]; total += (pkt[14] << 8) | pkt[15]; total += (pkt[16] << 8) | pkt[17]; total += (pkt[18] << 8) | pkt[19]; total += 6; // add protocol number total += newTcpHdrLen+tcpDataLen; // add TCP packet length // fold to 16 bits while ((total & 0xffff0000) != 0) { total = (total & 0xffff) + (total >> 16); } total = ~total; // take one's complement // replace the old checksum value with the new one pkt[ipHdrLen+16] = (total >> 8); pkt[ipHdrLen+17] = total & 0xff; // END: compute the TCP checksum // BEGIN: compute the IP checksum i = 0; total = 0; // 10 is the offset of the checksum field itself while (i < 10) { total += ((pkt[i] << 8) | pkt[i+1]); i += 2; } i = 12; // skip existing checksum field while (i < ipHdrLen) { total += ((pkt[i] << 8) | pkt[i+1]); i += 2; } // fold to 16 bits while ((total & 0xffff0000) != 0) { total = (total & 0xffff) + (total >> 16); } total = ~total; // one's complement // put the new checksum in place over the old one pkt[10] = (unsigned char)(total >> 8); pkt[11] = (unsigned char)(total & 0xff); // END: compute the IP checksum // print the bytes of the new, modified packet if (debug) { fprintf(stderr, "new packet:"); int i = 0; while (i<ipHdrLen+newTcpHdrLen+tcpDataLen) { if ((i%4) == 0) { fprintf(stderr, "\n "); } if ((i==ipHdrLen || i==ipHdrLen+newTcpHdrLen)) { fprintf(stderr, "----------\n "); } fprintf(stderr, "%02x ", pkt[i]); i++; } fprintf(stderr, "\n"); } // reinject the modified packet fprintf(stderr," reinjecting modified packet, length "+ newIpPktLen); status = ipq_set_verdict(h, m->packet_id, NF_ACCEPT, m->data_len, pkt); if (status < 0) die(h); break; } default: fflush(stderr); fflush(stdout); fprintf(stderr, "Unknown message type???\n"); fflush(stderr); fflush(stdout); break; } } while (1); ipq_destroy_handle(h); return 0; } ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: changing packet length? 2005-05-06 14:11 ` BJ Premore @ 2005-05-29 19:00 ` Harald Welte 2005-05-29 19:01 ` Harald Welte 1 sibling, 0 replies; 8+ messages in thread From: Harald Welte @ 2005-05-29 19:00 UTC (permalink / raw) To: BJ Premore; +Cc: netfilter-devel [-- Attachment #1: Type: text/plain, Size: 1307 bytes --] On Fri, May 06, 2005 at 10:11:59AM -0400, BJ Premore wrote: > Hi Harald, > > On Fri, May 06, 2005 at 01:14:10PM +0200, Harald Welte wrote: > > On Tue, May 03, 2005 at 05:34:06PM -0400, BJ Premore wrote: > > > So my hopefully simple question is, can packet sizes be > > > changed and then reinjected using ipq_set_verdict? > > > > Of course. you just reinject the packet with a different > > data_len. > > That's what I thought too, but I get the problems described > in my original post (subsequent packets start looking > mangled, basically). Have you, or has anyone, gotten this > to work? I've been scouring the net for examples but in no > case has any code that I've found actually changed the > length of the packets before reinjecting them. sorry for not getting back to you earlier. Does the problem still persist? could you send me pcap files of the packets before and after the ip_queue issue? -- - Harald Welte <laforge@netfilter.org> http://netfilter.org/ ============================================================================ "Fragmentation is like classful addressing -- an interesting early architectural error that shows how much experimentation was going on while IP was being designed." -- Paul Vixie [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: changing packet length? 2005-05-06 14:11 ` BJ Premore 2005-05-29 19:00 ` Harald Welte @ 2005-05-29 19:01 ` Harald Welte 2005-06-07 7:21 ` Quinton Hoole 1 sibling, 1 reply; 8+ messages in thread From: Harald Welte @ 2005-05-29 19:01 UTC (permalink / raw) To: BJ Premore; +Cc: netfilter-devel [-- Attachment #1: Type: text/plain, Size: 1275 bytes --] On Fri, May 06, 2005 at 10:11:59AM -0400, BJ Premore wrote: > Hi Harald, > > On Fri, May 06, 2005 at 01:14:10PM +0200, Harald Welte wrote: > > On Tue, May 03, 2005 at 05:34:06PM -0400, BJ Premore wrote: > > > So my hopefully simple question is, can packet sizes be > > > changed and then reinjected using ipq_set_verdict? > > > > Of course. you just reinject the packet with a different > > data_len. > > That's what I thought too, but I get the problems described > in my original post (subsequent packets start looking > mangled, basically). Have you, or has anyone, gotten this > to work? I've been scouring the net for examples but in no > case has any code that I've found actually changed the > length of the packets before reinjecting them. another thought: could you double-check (using strace) that the packets you reinject are exactly like they are supposed to be? -- - Harald Welte <laforge@netfilter.org> http://netfilter.org/ ============================================================================ "Fragmentation is like classful addressing -- an interesting early architectural error that shows how much experimentation was going on while IP was being designed." -- Paul Vixie [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: changing packet length? 2005-05-29 19:01 ` Harald Welte @ 2005-06-07 7:21 ` Quinton Hoole 0 siblings, 0 replies; 8+ messages in thread From: Quinton Hoole @ 2005-06-07 7:21 UTC (permalink / raw) To: Harald Welte; +Cc: BJ Premore, netfilter-devel Harald Welte wrote: >On Fri, May 06, 2005 at 10:11:59AM -0400, BJ Premore wrote: > > >>Hi Harald, >> >>On Fri, May 06, 2005 at 01:14:10PM +0200, Harald Welte wrote: >> >> >>>On Tue, May 03, 2005 at 05:34:06PM -0400, BJ Premore wrote: >>> >>> >>>>So my hopefully simple question is, can packet sizes be >>>>changed and then reinjected using ipq_set_verdict? >>>> >>>> >>>Of course. you just reinject the packet with a different >>>data_len. >>> >>> >>That's what I thought too, but I get the problems described >>in my original post (subsequent packets start looking >>mangled, basically). Have you, or has anyone, gotten this >>to work? I've been scouring the net for examples but in no >>case has any code that I've found actually changed the >>length of the packets before reinjecting them. >> >> > >another thought: could you double-check (using strace) that the packets >you reinject are exactly like they are supposed to be? > > I haven't looked into the detail of what you're doing, but I'm busy developing a netfilter target, and in the process realised that the kernel recalculates the IP header length, and ignores whatever header length I inject (i.e. if I increase the header length in order to have open space at the end of the IP options, it recalculates the length on the basis of the real option sit finds, and overwrites my increased header length). It could be doing something similar to your packet bodies. Just a thought. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: changing packet length? 2005-05-06 11:14 ` Harald Welte 2005-05-06 14:11 ` BJ Premore @ 2005-05-12 15:25 ` Todd Underwood 1 sibling, 0 replies; 8+ messages in thread From: Todd Underwood @ 2005-05-12 15:25 UTC (permalink / raw) To: netfilter-devel Harald, all, On Fri, May 06, 2005 at 01:14:10PM +0200, Harald Welte wrote: > On Tue, May 03, 2005 at 05:34:06PM -0400, BJ Premore wrote: > > So my hopefully simple question is, can packet sizes be > > changed and then reinjected using ipq_set_verdict? > > Of course. you just reinject the packet with a different data_len. > this seems not to work. given the code that was posted, the trivial case of this fails: adding 4 bytes of option-1 to the tcp header, changing the checksum and changing the size. the data gets corrupted. is there some simple bug that i'm not seeing the in the header/data handling code that was posted. running tcpdump, i see the same errors that bj was reporting. scouring the web i can find *no* examples of anyone changing the size of the header or the data in ipq userspace processes. without being able to do that, interesting things (like a userspace md5 signing implementation) are obviously not possible. harald: did you mean something by 'reinject' other than ipq_set_verdict, with new data? todd ^ permalink raw reply [flat|nested] 8+ messages in thread
* changing packet length? @ 2005-05-04 13:34 BJ Premore 0 siblings, 0 replies; 8+ messages in thread From: BJ Premore @ 2005-05-04 13:34 UTC (permalink / raw) To: netfilter Hi everyone. I've been pulling my hair out lately, using netfilter/ipq to try to add options to the TCP headers of outgoing packets. However, even just adding 4 bytes of no-op options results in subsequent incoming packets (via ipq_get_packet) looking mangled. (After adding the options, all appropriate fields were updated--checksums, length fields, etc. Also, I was extremely carefully to follow the specifications for adding the TCP options, proper padding, etc., etc. I'm pretty sure my problems do not have to do with the formatting of the packet.) So my hopefully simple question is, can packet sizes be changed and then reinjected using ipq_set_verdict? I found one reference that seemed to suggest that modified packets had to stay the same size. I've tested modifying packets without changing their overall byte sizes, and that does in fact seem to work (Eg, I changed the TTL field.). If the answer to the above question is 'yes', then I'll provide more details in the follow-up, in hopes of getting to the bottom of my troubles. Thanks in advance, -bj BJ Premore ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2005-06-07 7:21 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2005-05-03 21:34 changing packet length? BJ Premore 2005-05-06 11:14 ` Harald Welte 2005-05-06 14:11 ` BJ Premore 2005-05-29 19:00 ` Harald Welte 2005-05-29 19:01 ` Harald Welte 2005-06-07 7:21 ` Quinton Hoole 2005-05-12 15:25 ` Todd Underwood -- strict thread matches above, loose matches on Subject: below -- 2005-05-04 13:34 BJ Premore
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.