Networking - Assignment 3

Packet Filtering and Encryption

Johan IJsveld & Rick van der Zwet

      <jijsveld@xs4all.nl> & <hvdzwet@liacs.nl>

LIACS Leiden University Niels Bohrweg 1 2333 CA Leiden The Netherlands

29 april 2009

1 Implementation

We have chosen for a single emphC program without any arguments to keep it simple, meaning for the encryption key 0x12345678 will be hard-coded into the program and queue number are hard-coded 0 for input and 1 for output.

2 Global working

At first a package arrives at netfilter which is a Linux packet filter implementation. This will push the packet using callback function implemented at inlibnetfilter queue to our implementation. let’s call our application xorfilter for a moment. The xorfilter preforms it’s ’magic’ which will be in this case a mangle of the data payload using a XOR computation with the key above. Next it recalculates the TCP checksum to ensure the checksum matches the altered payload, leading to proper validation of the packet on the other end.

3 Usage xorfilter

At first make sure to enable the xorfilter, this needed to be running under the root user, due to the enhanced privileges it needs at start by ’hooking’ into iptables. Next alter iptables using the CLI script, for a reference sample, check setqueue.sh.

4 Usage echod

Ones started the program echod will listen at port 12345. It’s only purpose it serves (hences the ’d’ of daemon in echod) is to reply the data it receives. One could connect using the program telnet to the program using telnet localhost 12345 and everything you type will be returned as well.

5 xorfilter encryption

The key consist of 4 bytes, so for every 4 bytes, the data is XORed with the key, which is first translated using htonl to make sure we are using big endian instead of small endian as all network traffic is big endian by definition. Next in case of a remainder -when the length of the data is not a power of 4 bytesthe remainder is XORed with the relevant byte of the key. Example:

   DATA: AB CD EF 34 23 21 34 (7 bytes)
Step 1 (key repeated each 4 bytes, done using for loop on words):
   KEY : 12 34 56 78
   IMM : B9 F9 B9 4C 23 21 34
Step 2 (remainder key, done using for loop on bytes):
   KEY :             12 34 56
   IMM : B9 F9 B9 4C 31 15 62

Appendix

echod (1 file), xorfilter (9 files), netfilter CLI example (2 files)

01: /* Netlab 2009 - group 1 - assignment 3 02: * Johan IJsveld 03: * Rick van der Zwet

04: */
05: #include <sys/types.h>
06: #include <netdb.h>
07: #include <sysexits.h>
08: #include <stdio.h>
09: #include <string.h>
10: #include <unistd.h>
11:
12: #include <sys/socket.h>
13: #include <netinet/ip.h>
14: #include <netinet/tcp.h>
15:

16: #define LISTEN BACKLOG 0 17: #define BUF SIZE 1000

18:
19:
20: #include <signal.h>
21:
22:

23: int main() { 24: int conn fd; 25: char buf[BUF SIZE]; 26: ssize t recv size; 27: int retno;

28:

29: /* Create a tcp/ip socket */ 30: int mysocket = socket(PF INET, SOCK STREAM, 0);

31:

32: struct sockaddr in my addr; 33: struct sockaddr in their addr; 34: int sin size;

35:
36:

37: // ip(7) Create listen port, NOTE addresses in byte-order BYTEORDER(3) 38: my addr.sin family = AF INET; // By default 39: my addr.sin port = htons(12345); 40: my addr.sin addr.s addr = htonl(INADDR ANY); 41: memset(my addr.sin zero, '\0', sizeof my addr.sin zero);

42:

43: // get connected 44: retno = bind(mysocket, (struct sockaddr *) &my addr, sizeof(struct sockaddr in)); 45: retno = listen(mysocket, LISTEN BACKLOG); 46: sin size = sizeof(struct sockaddr in);

47:

48: // Make it a server, e.g. never ending 49: while(1) { 50: conn fd = accept(mysocket, (struct sockaddr *)&their addr, &sin size); 51: if (fork() == 0) { 52: // child will help to echo the stuff 53: while(1) { 54: retno = recv(conn fd, &buf, BUF SIZE, 0); 55: printf("%s\n", buf); 56: if (retno <= 0) 57: break; 58: retno = send(conn fd, &buf, retno, 0); 59: if (retno <= 0) 60: break;

61:  }

62: close(conn fd);

63:  }
64: }

65: close(mysocket);

66:
67:

68: return EX OK;

69: }
01: #include "checksum.h"
02:

03: long checksum( unsigned short *addr, int count )

04: {

05: /* Compute Internet Checksum for ”count” bytes

06:  *  beginning at location ”addr”.

07:  */

08: long checksum; 09: register long sum = 0; 10: while( count > 1 ) { 11: /* This is the inner loop */ 12: sum += * (unsigned short *) addr++; 13: count -= 2;

14:  }
15:

16: /* Add left-over byte, if any */ 17: if( count > 0 ) 18: sum += * (unsigned char *) addr;

19:

20: /* Fold 32-bit sum to 16 bits */ 21: while (sum>>16) 22: sum = (sum & 0xffff) + (sum >> 16); 23: checksum = ˜ sum; 24: return checksum;

25: }
26:

01: #ifndef CHECKSUM H 02: #define CHECKSUM H

03:

04: /* Compute Internet Checksum for ”count” bytes 05: * beginning at location ”addr”.

06: */

07: long checksum( unsigned short *addr, int count );

08:

09: #endif

10:
001: #include "filter.h"
002: #include "xorencrypt.h"
003: #include "checksum.h"
004:
005: #include <stdio.h>
006: #include <stdlib.h>
007: #include <string.h>
008: #include <unistd.h>
009:
010: #include <netinet/in.h>
011: #include <linux/types.h>
012: #include <linux/ip.h>
013: #include <linux/tcp.h>

014: #include <linux/netfilter.h> /* for NF ACCEPT */

015: #include <arpa/inet.h>
016: #include <inttypes.h>
017:

018: const unsigned int key = 0x12345678; /* The key used for encrypting */

019:

020: /* Returns the IP header from the datagram

021: */

022: struct iphdr *get ip hdr(char *datagram)

023: {

024: return (struct iphdr *)datagram;

025: }
026:

027: /* Returns the TCP header from the datagram

028: */

029: struct tcphdr *get tcp hdr(char *datagram)

030: {

031: char *tcpdata = datagram + get ip len(datagram); 032: return (struct tcphdr *)tcpdata;

033: }
034:

035: /* Returns pointer to TCP payload data from the datagram

036: */

037: char *get tcp payload(char *datagram)

038: {

039: struct tcphdr *tcphdr = get tcp hdr(datagram); 040: int iphdr len = get ip len(datagram); 041: int tcphdr len = get tcp len(tcphdr); 042: return datagram + iphdr len + tcphdr len;

043: }
044:

045: /* Returns the total length of the datagram

046: */

047: u16 get ip tot len(struct iphdr *ip)

048: {

049: return ntohs(ip->tot len);

050: }
051:

052: /* Returns the total length of the IP header

053: */

054: u16 get ip len(char *datagram)

055: {

056: struct iphdr *iphdr = get ip hdr(datagram); 057: return iphdr->ihl * 4; /* ihl is in words */

058: }
059:

060: /* Returns the length of the IP options field

061: */

062: u16 get ip opt len(char *datagram)

063: {

064: return get ip len(datagram) - sizeof(struct iphdr);

065: }
066:

067: /* Returns the total length of the TCP header

068: */

069: u16 get tcp len(struct tcphdr *tcphdr)

070: {

071: return tcphdr->doff * 4; /* data offset is in words */

072: }
073:

074: /* Returns the length of the TCP options field

075: */

076: u16 get tcp opt len(struct tcphdr *hdr)

077: {

078: return get tcp len(hdr) - sizeof(struct tcphdr);

079: }
080:

081: /* Returns the length in bytes of the tcp payload data

082: */

083: u16 get tcp data len(char *datagram)

084: {

085: struct iphdr *iphdr = get ip hdr(datagram); 086: struct tcphdr *tcphdr = get tcp hdr(datagram); 087: int total len = get ip tot len(iphdr); 088: int iphdr len = get ip len(datagram); 089: int tcphdr len = get tcp len(tcphdr); 090: return total len - iphdr len - tcphdr len;

091: }
092:

093: /* Returns the source address */ 094: u16 get tcp source(struct tcphdr *hdr)

095: {

096: return ntohs(hdr->source);

097: }
098:

099: /* Returns the destination address */ 100: u16 get tcp dest(struct tcphdr *hdr)

101: {

102: return ntohs(hdr->dest);

103: }
104:

105: /* the pseudo header used in calculating checksum */ 106: struct pseudo hdr { 107: u32 source; 108: u32 dest; 109: u8 zero; 110: u8 ptcl; 111: u16 tcplen;

112: };
113:

114: void print datagram(char *datagram)

115: {

116: struct iphdr *iphdr = get ip hdr(datagram); 117: struct tcphdr *tcphdr = get tcp hdr(datagram); 118: unsigned int iphdr len = get ip len(datagram); 119: unsigned int tcphdr len = get tcp len(tcphdr); 120: unsigned int total len = get ip tot len(iphdr); 121: unsigned int data len = get tcp data len(datagram); 122: char *data = get tcp payload(datagram);

123: printf("datagram length: %d, iphdr length: %d, tcphdr length: %d, data length: %d, data
pointer: %p, sizeof(struct pseude hdr): %d\n",

124: total len, iphdr len, tcphdr len, data len, data, sizeof(struct pseudo hdr));

125: }
126:
127:

128: /* Encrypts TCP payload data using XOR in the datagram pointed to by datagram

129: */

130: int encrypt payload(char *datagram)

131: {

132: struct iphdr *iphdr = get ip hdr(datagram); 133: struct tcphdr *tcphdr = get tcp hdr(datagram); 134: unsigned int tcphdr len = get tcp len(tcphdr); 135: unsigned int total len = get ip tot len(iphdr); 136: unsigned int data len = get tcp data len(datagram); 137: char *data = get tcp payload(datagram); 138: struct pseudo hdr *phdr; 139: long crc;

140:

141: print datagram(datagram); 142: if (iphdr->protocol != 6) {

143:  printf("not a tcp datagram\n");

144: return total len;

145:  }
146:

147: /* memset(data, 0, data len); */ 148: /* xor payload data */

149:  printf("Before crypt: '%s'\n", data);

150: xorencrypt(data, data len, htonl(key));

151:  printf("After crypt: '%s'\n", data);

                                                                                                    152:

153: printf("crc before: %d\n", tcphdr->check);

154: /* calculate new crc value by making new datagram with pseudo header */

155: tcphdr->check = 0;

156: char *copy = malloc(sizeof(struct pseudo hdr) + tcphdr len + data len);

                                                                                                    157:

158: /* set pseudo header */

159: phdr = (struct pseudo hdr *)copy;

160: phdr->source = iphdr->saddr; 161: phdr->dest = iphdr->daddr; 162: phdr->zero = 0; 163: phdr->ptcl = iphdr->protocol; 164: phdr->tcplen = tcphdr len + data len; 165: phdr->tcplen = htons(phdr->tcplen);

                                                                                                    166:

167: /* copy tcp header minus options */

168: memcpy(copy + sizeof(struct pseudo hdr), (char *)tcphdr, tcphdr len); 169: /* copy payload data */ 170: memcpy(copy + sizeof(struct pseudo hdr) + tcphdr len, data, data len);

                                                                                                    171:

172: /* calculate and set new crc */

173: crc = checksum((unsigned short *)copy, sizeof(struct pseudo hdr) + tcphdr len + data len); 174: free(copy);

                                                                                                    175:

176: tcphdr->check = ( u16)crc;

177: printf("crc after: %d\n", tcphdr->check);

178: return total len;

                                                                                                    179: }
                                                                                                    180:

01: #ifndef FILTER H 02: #define FILTER H

                                                                                                    03:
                                                                                                    04: #include <linux/types.h>
                                                                                                    05:

06: /* Returns the IP header from the datagram */ 07: struct iphdr *get ip hdr(char *datagram);

                                                                                                    08:

09: /* Returns the TCP header from the datagram */ 10: struct tcphdr *get tcp hdr(char *datagram);

                                                                                                    11:

12: /* Returns pointer to TCP payload data */ 13: char *get tcp payload(char *datagram);

                                                                                                    14:

15: /* Returns the total length of the datagram */

16: u16 get ip tot len(struct iphdr *ip);

                                                                                                    17:

18: /* Returns the total length of the IP header */

19: u16 get ip len(char *datagram);

                                                                                                    20:

21: /* Returns the length of the IP options field */

22: u16 get ip opt len(char *datagram);

                                                                                                    23:

24: /* Returns the total length of the TCP header */ 25: u16 get tcp len(struct tcphdr *tcphdr);

                                                                                                    26:

27: /* Returns the length of the TCP options field */ 28: u16 get tcp opt len(struct tcphdr *hdr);

                                                                                                    29:

30: /* Returns the length in bytes of the tcp payload data */

31: u16 get tcp data len(char *datagram);

                                                                                                    32:

33: /* Returns the source address */

34: u16 get tcp source(struct tcphdr *hdr);

                                                                                                    35:

36: /* Returns the destination address */

37: u16 get tcp dest(struct tcphdr *hdr);

                                                                                                    38:

39: /* Ecrypts TCP payload data using XOR in the datagram pointed to by data */ 40: int encrypt payload(char *datagram);

                                                                                                    41:

42: #endif

                                                                                                    43:
                                                                                                    001: #include "queue.h"
                                                                                                    002:
                                                                                                    003: #include <stdio.h>
                                                                                                    004: #include <stdlib.h>
                                                                                                    005: #include <unistd.h>
                                                                                                    006: #include <netinet/in.h>
                                                                                                    007: #include <sys/types.h>
                                                                                                    008: #include <sys/socket.h>
                                                                                                    009: #include <linux/types.h>

010: #include <linux/netfilter.h> /* for NF ACCEPT */

                                                                                                    011:
                                                                                                    012: #include <libnetfilter queue/libnetfilter queue.h>
                                                                                                    013:

014: #define MAX QUEUES 3

                                                                                                    015:

016: /* data for queue’s */

017: struct queue t {

018: struct nfq q handle *qh; /* handle to the queue */

019: callback cbp; /* callback function to handle packets from this queue */

020: int n;

                                                                                                    021: };
                                                                                                    022:

023: /* the queue’s that are setup */

024: static struct queue t queues[MAX QUEUES];

                                                                                                    025:

026: /* The main netlib handle and file descriptor */ 027: static struct nfq handle *h = NULL; 028: static int fd;

029:
030: /*

031: struct nfnl handle *nh;

032: */
033:

034: void init()

035: {
036:  printf("opening library handle\n");

037: h = nfq open(); 038: if (!h) {

039:  fprintf(stderr, "error during nfq open()\n");

040: exit(1);

041:  }
042:
043:  printf("unbinding existing nf queue handler for AF INET (if any)\n");

044: if (nfq unbind pf(h, AF INET) < 0) {

045:  fprintf(stderr, "error during nfq unbind pf()\n");

046: exit(1);

047:  }
048:
049:  printf("binding nfnetlink queue as nf queue handler for AF INET\n");

050: if (nfq bind pf(h, AF INET) < 0) {

051:  fprintf(stderr, "error during nfq bind pf()\n");

052: exit(1);

053:  }
054:

055: fd = nfq fd(h);

056: }
057:

058: void deinit()

059: {
060:  printf("closing library handle\n");

061: nfq close(h);

062: }
063:

064: /* callback called by netfilter queue when packet is available */ 065: static int cb(struct nfq q handle *qh, struct nfgenmsg *nfmsg, struct nfq data *nfa, void *data)

066: {

067: char *datagram; 068: int n = *(int *)data; 069: u int32 t id = print pkt(nfa); 070: u int32 t verdict; 071: int len;

072:
073:  printf("entering nfq callback\n");
074:

075: if (nfq get payload(nfa, &datagram) < 0) {

076:  fprintf(stderr, "error could not get payload data\n");

077: exit(1);

078:  }

079: verdict = queues[n].cbp(datagram, &len);

080:

081: return nfq set verdict(qh, id, verdict, len, (unsigned char *)datagram);

082: }
083:

084: void setup queue(int n, callback cbp)

085: {

086: if (n >= MAX QUEUES) {

087:  fprintf(stderr, "error not enough queues\n");

088: exit(1);

089:  }
090:
091:  printf("binding this socket to queue '%d'\n", n);

092: queues[n].n = n; 093: queues[n].qh = nfq create queue(h, n, &cb, &(queues[n].n)); 094: if (!queues[n].qh) {

095:  fprintf(stderr, "error during nfq create queue()\n");

096: exit(1);

097:  }
098:
099:  printf("setting copy packet mode\n");

100: if (nfq set mode(queues[n].qh, NFQNL COPY PACKET, 0xffff) < 0) {

101:  fprintf(stderr, "can't set packet copy mode\n");

102: exit(1);

103:  }

104: queues[n].cbp = cbp;

105: }
106:

107: void close queue(int n)

108: {

109: if (n >= MAX QUEUES) {

110:  fprintf(stderr, "error not enough queues\n");

111: exit(1);

112:  }
113:
114:  printf("unbinding from queue %d\n", n);

115: nfq destroy queue(queues[n].qh);

116:

117: #ifdef INSANE 118: /* normally, applications SHOULD NOT issue this command, since 119: * it detaches other programs/sockets from AF INET, too ! */

120:  printf("unbinding from AF INET\n");

121: nfq unbind pf(h, AF INET); 122: #endif

123: }
124:

125: void receive data()

                                                                                                    126: {

127: int rv;

128: char buf[66000] attribute ((aligned));

                                                                                                    129:

130: while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {

                                                                                                    131:  printf("\n--- pkt received ---\n");

132: nfq handle packet(h, buf, rv);

                                                                                                    133:  }
                                                                                                    134: }
                                                                                                    135:

136: /* Print packet and return packet id */ 137: u int32 t print pkt(struct nfq data *tb)

                                                                                                    138: {

139: int id = 0;

140: struct nfqnl msg packet hdr *ph; 141: struct nfqnl msg packet hw *hwph; 142: u int32 t mark, ifi; 143: int ret; 144: char *data;

                                                                                                    145:

146: ph = nfq get msg packet hdr(tb);

147: if (ph) {

148: id = ntohl(ph->packet id);

                                                                                                    149:  printf("hw protocol=0x%04x hook=%u id=%u ",

150: ntohs(ph->hw protocol), ph->hook, id);

                                                                                                    151:  }
                                                                                                    152:

153: hwph = nfq get packet hw(tb);

154: if (hwph) {

155: int i, hlen = ntohs(hwph->hw addrlen);

                                                                                                    156:
                                                                                                    157:  printf("hw src addr=");

158: for (i = 0; i < hlen-1; i++)

159: printf("%02x:", hwph->hw addr[i]); 160: printf("%02x ", hwph->hw addr[hlen-1]);

                                                                                                    161:  }
                                                                                                    162:

163: mark = nfq get nfmark(tb);

164: if (mark)

165: printf("mark=%u ", mark);

                                                                                                    166:

167: ifi = nfq get indev(tb);

168: if (ifi)

                                                                                                    169:  printf("indev=%u ", ifi);
                                                                                                    170:

171: ifi = nfq get outdev(tb);

172: if (ifi)

                                                                                                    173:  printf("outdev=%u ", ifi);

174: ifi = nfq get physindev(tb);

175: if (ifi)

                                                                                                    176:  printf("physindev=%u ", ifi);
                                                                                                    177:

178: ifi = nfq get physoutdev(tb);

179: if (ifi)

                                                                                                    180:  printf("physoutdev=%u ", ifi);
                                                                                                    181:

182: ret = nfq get payload(tb, &data);

183: if (ret >= 0)

                                                                                                    184:  printf("payload len=%d ", ret);
                                                                                                    185:

186: fputc('\n', stdout);

                                                                                                    187:

188: return id;

                                                                                                    189: }
                                                                                                    190:

01: #ifndef QUEUE H 02: #define QUEUE h

                                                                                                    03:
                                                                                                    04: #include <netinet/in.h>

05: #include <linux/netfilter.h> /* for NF ACCEPT */

                                                                                                    06:
                                                                                                    07: #include <libnetfilter queue/libnetfilter queue.h>
                                                                                                    08:

09: /* callback receives a datagram and returns a verdict (either NF ACCEPT or NF DROP) */ 10: typedef u int32 t (*callback)(char *datagram, int *len);

                                                                                                    11:

12: /* initialize netfilter */

13: void init();

                                                                                                    14:

15: /* deinitialize netfilter */

16: void deinit();

                                                                                                    17:

18: /* bind to queue n */

19: void setup queue(int n, callback cbp);

                                                                                                    20:

21: /* unbind from queue n */ 22: void close queue(int n);

                                                                                                    23:

24: /* start receiving packets */

25: void receive data();

                                                                                                    26:

27: /* Print packet and return packet id */

28: u int32 t print pkt (struct nfq data *tb);

                                                                                                    29:

30: #endif

                                                                                                    31:
                                                                                                    01: #include "xorencrypt.h"

03: typedef unsigned int key t;

04:

05: /* Encrypt data of len bytes with XOR and key */ 06: void xorencrypt(void *data, int len, key t key)

07: {

08: int i; 09: key t *word data = (key t *)data; 10: int word len = len / sizeof(key t); 11: int remainder = len % sizeof(key t);

12:

13: for (i = 0; i < word len; ++i) { 14: printf("%i\n", i ); 15: word data[i] ˆ = key;

16:  }
17:

18: for (i = len - remainder; i < len; ++i) { 19: ((unsigned char *)data)[i] ˆ = ((unsigned char*)&key)[i];

20:  }
21: }
22:

1: #ifndef XORENCRYPT H 2: #define XORENCRYPT H

3:

4: /* Encrypt data of len bytes with XOR and key */ 5: void xorencrypt(void *data, int len, unsigned int key);

6:

7: #endif

8:
01: #include <stdio.h>
02: #include <string.h>
03: #include "queue.h"
04: #include "filter.h"
05:
06: #include "xorencrypt.h"
07:

08: static u int32 t handle input(char *datagram, int *len)

09: {
10:  printf("encrypting input payload\n");

11: *len = encrypt payload(datagram); 12: return NF ACCEPT;

13: }
14:

15: static u int32 t handle output(char *datagram, int *len)

16: {
17:  printf("encrypting output payload\n");

18: *len = encrypt payload(datagram); 19: return NF ACCEPT;

20: }
21:

22: int main(void)

23: {

24: init();

25:

26: setup queue(1, handle input); 27: setup queue(2, handle output);

28:

29: receive data();

30:

31: close queue(1); 32: close queue(2);

33:

34: deinit();

35:

36: return 0;

37: }
38:

1: #!/bin/sh 2: /sbin/iptables -t mangle -A INPUT -i lo -j NFQUEUE --queue-num 0 3: /sbin/iptables -t mangle -A OUTPUT -o lo -j NFQUEUE --queue-num 1

4:

5: /sbin/iptables -t mangle -A INPUT -i eth0 -j NFQUEUE --queue-num 0 6: /sbin/iptables -t mangle -A OUTPUT -o eth0 -j NFQUEUE --queue-num 1

7:

8: #/sbin/iptables -t mangle -A INPUT -i eth0 -d 10.211.55.4 -j NFQUEUE --queue-num 1 9: #/sbin/iptables -t mangle -A OUTPUT -o eth0 -s 10.211.55.4 -j NFQUEUE --queue-num 2

1: #!/bin/sh 2: /sbin/iptables -F 3: /sbin/iptables -t mangle -F

4: