昨天修了车之后好多了,前拨链器能正常变速,下坡的时候速度可以更快了。听着耳边呼呼的风声,看着前面的路一点点消失有一点点出现,这种感觉不错。
今天去学校没有用GPS,路上也没有迷路,回来的时候还抄了近道。下午又去了趟Barkarby,仍然没有用GPS,去的时候虽然绕了点儿,但回来的时候异常顺利。
买了码表、前灯、水壶等物,还买了把长的螺丝刀和尖嘴钳,以后就算链条卡住了也不会怕了。
Leave a CommentJack of all trades, Doctor of Philosophy.
昨天修了车之后好多了,前拨链器能正常变速,下坡的时候速度可以更快了。听着耳边呼呼的风声,看着前面的路一点点消失有一点点出现,这种感觉不错。
今天去学校没有用GPS,路上也没有迷路,回来的时候还抄了近道。下午又去了趟Barkarby,仍然没有用GPS,去的时候虽然绕了点儿,但回来的时候异常顺利。
买了码表、前灯、水壶等物,还买了把长的螺丝刀和尖嘴钳,以后就算链条卡住了也不会怕了。
Leave a Comment掐指一算又有一周没有更新博客了,不是自己太懒,最近也算不上特别忙,原因是我有了新的让我释放精力的事情:骑车。
上周买了辆自行车,二手的旅行车,27速。车还行,可是原来的主人保养得不太好。第一天我买了车之后从绿线下面一个叫Bandhagen的地铁站,通过手机里GPS的帮助,费尽周折骑到了Kista。中间链条卡了两次,第一次是我刚骑了不到200米时,变速没变成,链条到卡在了两片牙盘中间。幸好附近有住户,我找一位大哥借了螺丝刀,将链条撬了出来。骑行十多公里之后,我再次试图使用前拨链器,不幸的是链条再一次卡住了。这次更悲剧,因为我当时在一片大森林里面,而GPS显示离我家还有4千米。在多次尝试将链条拔出来而都已失败告终之后,我推着车些许沮丧的往前走。
走了大概不到一千米,看到有位卡车司机在一个类似于采石场的地方洗车。于是我上前找他借了螺丝刀,在他的帮助下把链条弄出来了。一路骑行到家无话。
第二天下午骑车去了主校区,去的时候花了大约一个小时,中间迷路了15分钟左右,虽然我仍然是拿着GPS……回来的时候穿过了一大片墓地,很大一片,里面有各种各样的墓碑,大的小的,方的椭圆的,还有刚挖的坟墓。当然,这也是GPS干的好事。穿出来之后又一次迷路了,因为GPS让我横穿高速公路,我怕死,没敢过,在附近绕了半个多小时,终于找到了回家的路。等我在森林里面骑行的时候,天差不多已经黑了。特别是森林里面都是树,都看不到天。
后来又骑车到了IKEA附近,在Jula买了修车工具。回来之后连续修了两天的车,昨天差不多已经修好了的,不幸的是今天下午链条再次卡在了牙盘之间。于是我又修了一下午加一晚上,似乎我修车的时间比我骑车的时间都要长。
一个插曲,晚上出去试车时突然有只有些像狗友有些像鹿不过没角的奇怪动物从离我20米的地方横穿过车道,吓得我一大跳。
最近虽然比较累,但至少每天在做事。不似前些日子那么空虚无聊,不用去想那些不着边际的问题,这种感觉不错。
以上。
Leave a Comment今天把博客转移到这个站点了,因为以前的博客太像个博客了,不专业,不符合我爱装B的个性。于是就转移到这里了。
以前的博客已经不可访问(当然我自己是可以的),那个博客会显示站点已经转移,指向现在的网站。
估计这几天还得折腾这个东东。
Leave a Comment捣鼓了两三天,总算把自己这个域名的首页建好了,结束了长达四个月没有像样首页的状态。
首页用Joomla!系统管理,主要列出了我做过的项目和一些小玩意,目的只是为了展示自己,当然自己有几斤几两我是十分清楚的。所以请看过之后不必对我表示鄙视或者仰慕,但是如果有建设性的意见,我一定会欣然接受的。
Joomla!系统总体来说还是很不错的,容易上手,而且开源且支持扩展。目前来说易用性还有可改进的地方,但相信不久就会有相应的更新或者扩展来让它更加好用。
最近还在上瑞典语课,但这几天感觉没有什么进步,一直在复习以前学过的内容,而且课程组织的也没有上个月的好,甚至可以说是杂乱无章。我基本不知道现在在学习什么内容,比较痛苦的是现在词汇量还没有跟上,发音也没有系统的巩固。
中午在地铁站碰见上个月教我瑞典语的老太太,她上来第一句寒暄我就没有听懂。厚着脸皮说了句“Ursäkta?”老太太只好无奈的换成英文问候。
知不足而后进,所以这个周末我要好好补习一下,争取能有长足进展。
Leave a CommentI wrote a paper on privacy control in social networking sites. You can find the full paper at http://www.cse.hut.fi/en/publications/B/11/papers/li.pdf. Here’s the abstract:
As social networking services become increasingly popular, more and more attacks against users’ private information are reported. As a result, privacy protection becomes an important concern among users. Previous research has produced many different approaches to deal with privacy control in different social networking sites. In this paper, we make a survey on different approaches proposed to tackle the privacy issue in social networking sites. In particular, we put current approaches into three general categories, i.e. approaches addressing end users’ active participation, security automation based on machine learning algorithms, and privacy preserving by using a decentralized architecture for social networkingservices. Then we introduce and analyze some of the approaches in each category. Finally, we give some suggestions that may help privacy control in online social networks.
Leave a CommentStatic testing is used to test the bouncer, that is, a separate set of test cases and sample outputs are provided. And the bouncer is given the test cases and its outputs are compared with sample outputs.
A verifier is used to accomplish the above function, and another bash script is written to automate the process.
The bash script is as follows:
#!/bin/sh USAGE="Usage: $0 [-v] bouncer" CMD="./verifier " TESTDIR="cases" while getopts "v" optname do case "$optname" in "v") CMD="./verifier -v " ;; *) echo $USAGE exit 1 ;; esac done shift $(($OPTIND-1)) BCER=$* if [ -f "$BCER" ] then find "$TESTDIR" -iname "*pcap" | while read i do if [ -f "$i" ] && [ -f "$i"-ref ] then echo "======================================================================" echo "Verifying file: $i" $BCER -t -l 1.1.1.1 -s 3.3.3.3 <"$i" >"$i"-out BCRT=$? echo "----------------------------------------------------------------------" if [ $BCRT != 0 ] then echo "$BCER returned with $?" echo "Exiting $0" exit 1 fi $CMD -i "$i"-out -r "$i"-ref CMDRT=$? echo "----------------------------------------------------------------------" echo "Result for $i:" echo "$CMDRT packets has passed validation" echo "======================================================================" echo "n" fi done else echo $USAGE fi exit 0
The verifier is as follows:
#include "verifier.h" typedef unsigned short u16; typedef unsigned long u32; /* CRC * Adopted from http://www.netfor2.com/ipsum.htm */ u16 ip_sum_calc(u16 len_ip_header, u16 buff[]) { u16 word16; u32 sum = 0; u16 i; // make 16 bit words out of every two adjacent 8 bit words in the packet // and add them up for (i = 0; i < len_ip_header; i = i + 2) { word16 = ((buff[i] << 8)&0xFF00)+(buff[i + 1]&0xFF); sum = sum + (u32) word16; } // take only 16 bits out of the 32 bit sum and add up the carries while (sum >> 16) sum = (sum & 0xFFFF)+(sum >> 16); // one's complement the result sum = ~sum; return ((u16) sum); } int usage() { fprintf(stderr, "Usage: verifier [-v] -i input_file -r reference_filen"); exit(1); } int main(int argc, char **argv) { int verbose = 0; opterr = 0; char c; char *ifilename, *rfilename; struct stat st; while ((c = getopt(argc, argv, "vi:r:")) != -1) { if (c == 'i') { ifilename = optarg; if (stat(ifilename, &st) != 0) { fprintf(stderr, "File does not exist!n"); exit(1); } } else if (c == 'r') { rfilename = optarg; if (stat(rfilename, &st) != 0) { fprintf(stderr, "File does not exist!n"); exit(1); } } else if (c == 'v') { verbose = 1; } else { usage(); } } pcap_t *ihandle = NULL, *rhandle = NULL; char errbufi[PCAP_ERRBUF_SIZE], errbufr[PCAP_ERRBUF_SIZE]; ihandle = pcap_open_offline(ifilename, errbufi); rhandle = pcap_open_offline(rfilename, errbufr); struct pcap_pkthdr ihdr, rhdr; const u_char *ipkt, *rpkt; ipkt = malloc(MAX_PACKET_SIZE); rpkt = malloc(MAX_PACKET_SIZE); if (ipkt == NULL || rpkt == NULL) { perror("malloc"); exit(1); } int pc = -1; /* Packet counter */ char flags[MAX_PACKETS_NO]; /* Broken or Not */ memset(flags, PKT_OK, MAX_PACKETS_NO); while ((ipkt = pcap_next(ihandle, &ihdr)) && (rpkt = pcap_next(rhandle, &rhdr))) { pc++; /* Typecasting input packet*/ const struct sniff_ethernet *iethernet; /* The ethernet header */ const struct sniff_ip *iip; /* The IP header */ const struct sniff_icmp *iicmp; /* The ICMP header */ const char *ipayload; /* Packet payload */ u_int isize_ip; iethernet = (struct sniff_ethernet*) (ipkt); iip = (struct sniff_ip*) (ipkt + SIZE_ETHERNET); isize_ip = IP_HL(iip)*4; if (isize_ip < 20) { fprintf(stderr, " * Invalid IP header length: %u bytesn", isize_ip); continue; } iicmp = (struct sniff_icmp*) (ipkt + SIZE_ETHERNET + isize_ip); ipayload = (char *) (ipkt + SIZE_ETHERNET + isize_ip + SIZE_ICMP); /* Typecasting reference packet*/ const struct sniff_ethernet *rethernet; /* The ethernet header */ const struct sniff_ip *rip; /* The IP header */ const struct sniff_icmp *ricmp; /* The ICMP header */ const char *rpayload; /* Packet payload */ u_int rsize_ip; rethernet = (struct sniff_ethernet*) (rpkt); rip = (struct sniff_ip*) (rpkt + SIZE_ETHERNET); rsize_ip = IP_HL(rip)*4; if (rsize_ip < 20) { fprintf(stderr, " * Invalid IP header length: %u bytesn", rsize_ip); continue; } ricmp = (struct sniff_icmp*) (rpkt + SIZE_ETHERNET + rsize_ip); rpayload = (char *) (rpkt + SIZE_ETHERNET + rsize_ip + SIZE_ICMP); /* Here comes the validation process */ /* Check IP checksum */ u16 ipbuf[isize_ip]; u16 ipsum = ntohs(iip->ip_sum); int i; for (i = 0; i < isize_ip; i++) { if (i == 10 || i == 11) ipbuf[i] = 0x00; else ipbuf[i] = *((u_char *) (ipkt + SIZE_ETHERNET + i)); } if (ipsum != ip_sum_calc(isize_ip, ipbuf)) { flags[pc] = ERR_IP_SUM; continue; } /* Check ICMP checksum */ int plen = ihdr.len - SIZE_ETHERNET - isize_ip - 8; u16 icmpbuf[8 + plen]; u16 icmpsum = ntohs(iicmp->icmp_sum); for (i = 0; i < 8; i++) { if (i == 2 || i == 3) icmpbuf[i] = 0x00; else icmpbuf[i] = *((u_char *) (ipkt + SIZE_ETHERNET + isize_ip + i)); } for (i = 0; i < plen; i++) { icmpbuf[i + 8] = *((u_char *) (ipayload + i)); } if (icmpsum != ip_sum_calc(8 + plen, icmpbuf)) { flags[pc] = ERR_ICMP_SUM; continue; } /* Check IP TTL */ if (iip->ip_ttl <= 0) { flags[pc] = ERR_IP_TTL; continue; } /* Check IP source address */ if (iip->ip_src.s_addr != rip->ip_src.s_addr) { flags[pc] = ERR_IP_SADDR; continue; } /* Check IP destinataion address */ if (iip->ip_dst.s_addr != rip->ip_dst.s_addr) { flags[pc] = ERR_IP_DADDR; continue; } /* Check ICMP type */ if (iicmp->icmp_type != ricmp->icmp_type) { flags[pc] = ERR_ICMP_TYPE; continue; } /* Check ICMP ID */ if (iicmp->icmp_id != ricmp->icmp_id) { flags[pc] = ERR_ICMP_ID; continue; } /* Check ICMP sequence number */ if (iicmp->icmp_sequence != ricmp->icmp_sequence) { flags[pc] = ERR_ICMP_SEQ; continue; } } pc++; int bc = 0; /* Broken packet counter */ int i; for (i = 1; i <= pc; i++) { if (flags[i-1]) bc++; if (verbose) { switch (flags[i-1]) { case PKT_OK: fprintf(stdout, "Validation passed: %d/%dn", i, pc); break; case ERR_IP_SUM: fprintf(stdout, "IP checksum failed: %d/%dn", i, pc); break; case ERR_IP_TTL: fprintf(stdout, "IP TTL check failed: %d/%dn", i, pc); break; case ERR_IP_SADDR: fprintf(stdout, "IP source address check failed: %d/%dn", i, pc); break; case ERR_IP_DADDR: fprintf(stdout, "IP destination address check failed: %d/%dn", i, pc); break; case ERR_ICMP_SUM: fprintf(stdout, "ICMP checksum failed: %d/%dn", i, pc); break; case ERR_ICMP_TYPE: fprintf(stdout, "ICMP type check failed: %d/%dn", i, pc); break; case ERR_ICMP_ID: fprintf(stdout, "IP ID check failed: %d/%dn", i, pc); break; case ERR_ICMP_SEQ: fprintf(stdout, "IP sequence check failed: %d/%dn", i, pc); break; default: fprintf(stderr, "ERROR: Unknwon error type.n"); break; } } } if (bc == 0) fprintf(stdout, "%d packets passed validationn", pc); else fprintf(stdout, "%d out of %d packets failed validationn", bc, pc); /* Return number of packets passed validation */ return (pc - bc); }Leave a Comment
We define a BPF filter as “icmp and dst host <bouncer_ip>”, which filters out all none-ICMP packets and packets not destined to the bouncer. The we compile this filter and set the filter to the capture device.
When the capture device captures a packet, a process_pkt function is called to process the packet. And that is where we validate the packets and then, if the packet is valid, update
the packet and then send it out, or write the packet to a dump file.
The process of validating the packets are as follows:
Since we write the packet to a dump file in a separate function, so a pointer to the dump file handler is passed to the processing function when the process_pkt function is called. The same method is used to pass server IP address and test mode flag.
We keep a linked list of all the ICMP echo requests. When a ICMP echo reply is received, we go through the linked list to find out where
the original echo request comes from.
The code is as follows.
bouncer.h:
/* Global definitions for the port bouncer * Packet headers and so on */ #define _BSD_SOURCE 1 #include#include #include #include #include /* PCAP declarations*/ #include /* Standard networking declaration */ #include #include #include /* * The following system include files should provide you with the * necessary declarations for Ethernet, IP, and TCP headers */ #include #include #include #include /* Add any otherdeclarations you may need here... */ #define MAX_PACKET_SIZE 65535 /* Ethernet addresses are 6 bytes */ //#define ETHER_ADDR_LEN 6 /* Ethernet header */ struct sniff_ethernet { u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */ u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */ u_short ether_type; /* IP? ARP? RARP? etc */ }; /* IP header */ struct sniff_ip { u_char ip_vhl; /*version << 4 | header length >> 2 */ u_char ip_tos; /* type of service */ u_short ip_len; /* total length */ u_short ip_id; /* identification */ u_short ip_off; /* fragment offset field */ #define IP_RF 0x8000 /* reserved fragment flag */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_char ip_ttl; /*time to live */ u_char ip_p; /* protocol */ u_short ip_sum; /* checksum */ struct in_addr ip_src, ip_dst; /* source and dest address */ }; #define IP_HL(ip) (((ip)->ip_vhl) & 0x0f) #define IP_V(ip) (((ip)->ip_vhl) >> 4) /* ICMP header */ struct sniff_icmp { u_char icmp_type; #define ICMP_ECHO 0x8 #define ICMP_REPLY 0x0 u_char icmp_code; u_int16_t icmp_sum; u_int16_t icmp_id; u_int16_t icmp_sequence; }; #define SIZE_ETHERNET 14 #define SIZE_ICMP 8 #define IP_QUAD(ip) (ip)>>24,((ip)&0x00ff0000)>>16,((ip)&0x0000ff00)>>8,((ip)&0x000000ff) struct request{ struct request* next; struct sniff_ip* ip; struct sniff_icmp* icmp; };
process_pkt.c:
#include "bouncer.h" /* CRC * Adopted from http://www.netfor2.com/ipsum.htm */ typedef unsigned short u16; typedef unsigned long u32; u16 ip_sum_calc(u16 len_ip_header, u16 buff[]) { u16 word16; u32 sum =0; u16 i; // make 16 bit words out of every two adjacent 8 bit words in the packet // and add them up for (i = 0; i < len_ip_header; i = i + 2) { word16 = ((buff[i] << 8)&0xFF00)+(buff[i + 1]&0xFF); sum = sum + (u32) word16; } // take only 16 bits out of the 32 bit sum and add up the carries while (sum >> 16) sum = (sum & 0xFFFF)+(sum >> 16); // one'scomplement the result sum = ~sum; return ((u16) sum); } void process_pkt(u_char *args, struct pcap_pkthdr *header, u_char *packet) { if(header->caplen < header->len){ fprintf(stderr, "ERROR: Packet data not captured completely\n"); return; } /* Main function to perform the bouncing */ u_char testmode = *args; char *serv_addr = (char *) (args + 1); u_int32_t dst_addr =inet_addr(serv_addr); //pcap_dumper_t *dumper = NULL; u_char *dumper = NULL; memcpy(&dumper, args + 2 + strlen(serv_addr), sizeof (pcap_dumper_t *)); struct request ** prequests = NULL; memcpy(&prequests, args + 2 + strlen(serv_addr) + sizeof (pcap_dumper_t *), sizeof (struct request**)); //struct request *requests = *prequests; /* Typecasting packet*/ struct sniff_ethernet *ethernet; /* The ethernet header */ struct sniff_ip *ip; /* The IP header */ struct sniff_icmp *icmp; /* The ICMP header */ char *padding; /* Packet padding */ u_int size_ip; ethernet = (struct sniff_ethernet*) (packet); ip = (struct sniff_ip*) (packet + SIZE_ETHERNET); size_ip = IP_HL(ip)*4; u_int32_t srcip = ntohl(ip->ip_src.s_addr); if (size_ip < 20 || size_ip > header->len - SIZE_ETHERNET) { fprintf(stderr, "ERROR: Invalid IP header length: %ubytes\n", size_ip); if (testmode == 1) { header->caplen = 0; header->len = 0; pcap_dump(dumper, header, packet); } return; } icmp = (struct sniff_icmp*) (packet + SIZE_ETHERNET + size_ip); padding = (u_char *) (packet + SIZE_ETHERNET + size_ip + SIZE_ICMP); /* Validate the packet */ /* Validate IP header */ /* Check IP version */ u_char v = ip->ip_vhl>> 4; if(v != 4){ fprintf(stderr, "ERROR: Wrong IP verison %d\n", v); return; } /* Validate CRC */ u16 ipbuf[size_ip]; u16 ipsum = ntohs(ip->ip_sum); int i; for (i = 0; i < size_ip; i++) { if (i == 10 || i == 11) ipbuf[i] = 0x00; else ipbuf[i] = *((u_char *) (packet + SIZE_ETHERNET + i)); } if (ipsum != ip_sum_calc(size_ip, ipbuf)) { fprintf(stderr, "ERROR: ip checksum mismatch. Dropping packet from %u.%u.%u.%u\n", IP_QUAD(srcip)); if (testmode == 1) { header->caplen = 0; header->len = 0; pcap_dump(dumper, header, packet); } return; } /* Validate TTL */ if (ip->ip_ttl <= 0) { fprintf(stderr, "ERROR: ip TTL expired. Dropping packet from %u.%u.%u.%u\n", IP_QUAD(srcip)); if (testmode == 1) { header->caplen = 0; header->len = 0; pcap_dump(dumper, header, packet); } return; } /* Validate IP source address */ if (srcip == 0x00000000 || srcip >= 0xE0000000 || (srcip & 0x000000FF) == 0x000000FF || (srcip & 0x000000FF) == 0x00000000) { fprintf(stderr, "ERROR: ip source address invalid. Dropping packetfrom %u.%u.%u.%u\n", IP_QUAD(srcip)); if (testmode == 1) { header->caplen = 0; header->len = 0; pcap_dump(dumper, header, packet); } return; } /* Validate ICMP header */ /* Validate ICMP type and code */ if (!(icmp->icmp_code == 0 && (icmp->icmp_type == 0 || icmp->icmp_type == 8))) { fprintf(stderr, "ERROR: icmp type orcode unsupported. Dropping packet from %u.%u.%u.%u\n", IP_QUAD(srcip)); if (testmode == 1) { header->caplen = 0; header->len = 0; pcap_dump(dumper, header, packet); } return; } /* Validate CRC */ int plen = header->len - SIZE_ETHERNET - size_ip - 8; u16 icmpbuf[8 + plen]; u16 icmpsum = ntohs(icmp->icmp_sum); for (i = 0; i < 8;i++) { if (i == 2 || i == 3) icmpbuf[i] = 0x00; else icmpbuf[i] = *((u_char *) (packet + SIZE_ETHERNET + size_ip + i)); } for (i = 0; i < plen; i++) { icmpbuf[i + 8] = *((u_char *) (padding + i)); } if (icmpsum != ip_sum_calc(8 + plen, icmpbuf)) { fprintf(stderr, "ERROR: icmp checksum mismatch. Dropping packet from %u.%u.%u.%u\n", IP_QUAD(srcip)); if(testmode == 1) { header->caplen = 0; header->len = 0; pcap_dump(dumper, header, packet); } return; } /* Update the packet */ if (icmp->icmp_type == 0) { /* ICMP echo reply */ ip->ip_src.s_addr = ip->ip_dst.s_addr; /* Search the linked list for client address */ if (*prequests == NULL) { fprintf(stderr, "ERROR: process_pkt: nullrequest linked list\n"); return; } else { /* Find where the request comes from */ struct request *r; for (r = *prequests; r != NULL; r = r->next) { if (r->icmp->icmp_id == icmp->icmp_id && r->icmp->icmp_sequence == icmp->icmp_sequence) { ip->ip_dst.s_addr = r->ip->ip_src.s_addr; break; } } if (r == NULL) { fprintf(stderr, "ERROR: no match echo requests in stack\n"); return; } /* Remove the request from the linked list */ struct request *rr = *prequests; if (rr == r) { free(rr->icmp); free(rr->ip); *prequests = r->next; free(r); } else { while (rr!= r) rr = rr->next; free(rr->icmp); free(rr->ip); rr->next = r->next; free(r); } } } else { /* ICMP echo request */ /* Add new request to linked list */ struct request *r; r = malloc(sizeof (struct request)); if (r == NULL) { perror("ERROR: process_pkt:malloc"); return; } struct sniff_ip *ipt = malloc(sizeof (struct sniff_ip)); if (ipt == NULL) { perror("ERROR: process_pkt: malloc"); return; } memcpy(ipt, ip, sizeof (struct sniff_ip)); r->ip = ipt; struct sniff_icmp* icmpt = malloc(sizeof (struct sniff_icmp)); if (icmpt == NULL) { perror("ERROR: process_pkt: malloc"); return; } memcpy(icmpt, icmp, sizeof (struct sniff_icmp)); r->icmp = icmpt; r->next = *prequests; *prequests = r; /* Update destination address */ ip->ip_src.s_addr = ip->ip_dst.s_addr; ip->ip_dst.s_addr = dst_addr; } /* Recaculate CRC */ for (i = 0; i < size_ip; i++) { if (i == 10 || i == 11) ipbuf[i] = 0x00; else ipbuf[i] = *((u_char *) (packet + SIZE_ETHERNET + i)); } ip->ip_sum = htons(ip_sum_calc(size_ip, ipbuf)); if (testmode == 0) { pcap_t *handle = NULL; char errbuf[PCAP_ERRBUF_SIZE], *device = "tap0"; memset(errbuf, 0, PCAP_ERRBUF_SIZE); if ((handle = pcap_open_live(device, MAX_PACKET_SIZE, 1, 512, errbuf)) == NULL) { fprintf(stderr, "ERROR: %s\n", errbuf); exit(1); } /*Send the packet to network */ if (pcap_sendpacket(handle, packet, header->len) != 0) { perror("ERROR: process_pkt: pcap_sendpacket"); exit(1); } pcap_close(handle); fprintf(stderr, "Bouncer: packet sent\n"); } else { /* Or put it back on stdout */ int i = 0; for (i = 0; i < ETHER_ADDR_LEN; i++) ethernet->ether_shost[i] = 1; if(icmp->icmp_type == 0) { for (i = 0; i < ETHER_ADDR_LEN; i++) ethernet->ether_dhost[i] = 2; } else if (icmp->icmp_type == 8) { for (i = 0; i < ETHER_ADDR_LEN; i++) ethernet->ether_dhost[i] = 3; } pcap_dump(dumper, header, packet); //////////////////////////////////////////////////////////////////////// /* pcap_t *handle = NULL; char errbuf[PCAP_ERRBUF_SIZE], *device = "tap0"; memset(errbuf, 0, PCAP_ERRBUF_SIZE); if ((handle = pcap_open_live(device, MAX_PACKETS_NO, 1, 512, errbuf)) == NULL) { fprintf(stderr, "ERROR: %s\n", errbuf); exit(1); } if (pcap_sendpacket(handle, packet, header->len) != 0) { perror("ERROR: process_pkt: pcap_sendpacket"); exit(1); } pcap_close(handle); fprintf(stderr, "Packet sent\n"); */ //////////////////////////////////////////////////////////////////////// } return; }Leave a Comment
A bouncer bounces packets it receives from clients to servers. This is useful when people want to hide their internal network topologies. In this report, we examine a very simple case of bouncer — a bouncer that only bounces ICMP requests. When it receives an ICMP echo request, it modify the packet and forward it to the server specified by the user. After receiving the echo reply packet, it
again modifies the packet and finds out where to send the packet and then sends out the reply packet.
The code looks as follows.
#includeLeave a Comment#include #include #include #include #include #include #include #include #include #include #include #include #include #include "event.h" #include "rudp.h" #include "rudp_api.h" //#define DROP 3 rudp_socket_t rs_head = NULL; peer_t find_peer(peer_t *firstp, structsockaddr_in* sa) { peer_t p; //int pc = 0; for (p = *firstp; p != NULL; p = p->next) { //printf("peer count: %d\n", ++pc); if (memcmp(p->sa, sa, sizeof (struct sockaddr_in)) == 0) return p; } //printf("peer not found, creating new peer\n"); p = malloc(sizeof (struct peer)); if (p == NULL) { perror("find_peer: malloc"); return NULL; } struct sockaddr_in*sin; sin = malloc(sizeof (struct sockaddr_in)); if (sin == NULL) { perror("peerfind: malloc"); return NULL; } memcpy(sin, sa, sizeof (struct sockaddr_in)); p->sa = sin; p->packets = NULL; p->status = PEER_STATUS_INIT; p->sb = 0; p->sm = RUDP_WINDOW - 1; p->sn = 0; p->next = (*firstp); *firstp = p; return p; } int remove_peer(peer_t *firstp,peer_t rp) { peer_t p, *pp; pp = firstp; for (p = *firstp; p != NULL; p = p->next) { if (p == rp) { *pp = rp->next; free(rp->sa); free(rp); return 0; } pp = &p->next; } return -1; } /* * Add packet into a linked list. * Inserted in a way that packets with smaller seqno are always placed in front */ int add_packet(packet_t*packet_head, packet_t *pkt) { if (*packet_head == NULL) { (*pkt)->next = *packet_head; *packet_head = *pkt; } else { packet_t *p = malloc(sizeof (packet_t)); for ((*p) = *packet_head; (*p) != NULL; (*p) = (*p)->next) { if ((*pkt)->header->seqno == (*p)->header->seqno + 1) { (*pkt)->next = (*p)->next; (*p)->next = *pkt; break; } } //return -1; } //printf("packet added: %d type %d\n", (*pkt)->header->seqno, (*pkt)->header->type); return 0; } /* * Remove a packet from a linked list */ int remove_packet(packet_t *packet_head, packet_t pkt) { packet_t p, *pp; pp = packet_head; for (p = *packet_head; p != NULL; p = p->next) { if (pkt == p) { //printf("packet seq no %d removed\n",pkt->header->seqno); *pp = p->next; free(p); return 0; } pp = &p->next; } return -1; } /* * rudp_socket: Create a RUDP socket. * May use a random port by setting port to zero. */ rudp_socket_t rudp_socket(int port32) { int sockfd; sockfd = socket(PF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("rudp_socket: socket"); return NULL; } struct sockaddr_in *sin; sin = malloc(sizeof (struct sockaddr_in)); if (sin == NULL) { perror("rudp_socket: malloc"); return NULL; } sin->sin_addr.s_addr = htonl(INADDR_ANY); //sin->sin_addr.s_addr = inet_addr("127.0.0.1"); sin->sin_family = AF_INET; uint16_t port = port32; if (port == 0) { srand(time(0)); port = (rand() % (65535 - 1024)) + 1024; sin->sin_port = htons(port); while (bind(sockfd, (struct sockaddr*) sin, sizeof (struct sockaddr_in)) < 0) { port = (rand() % (65535 - 1024)) + 1024; sin->sin_port = htons(port); } } else { sin->sin_port = htons(port); if (bind(sockfd, (struct sockaddr*) sin, sizeof (struct sockaddr_in)) < 0) { perror("rudp_socket: bind"); return NULL; } } //printf("rudp_socket: bind successfully on port: %d\n", port); rudp_socket_t rs; rs = malloc(sizeof (struct rudp_socket)); if (rs == NULL) { perror("rudp_socket: malloc"); return NULL; } rs->sockfd = sockfd; rs->peers = NULL; rs->next = rs_head; rs_head = rs; /* int rc = 0; rudp_socket_t prs; for(prs = rs_head; prs != NULL; prs =prs->next) printf("rudp socket count: %d\n", ++rc); */ event_fd(rs->sockfd, rudp_listen, rs, "rudp_listen"); return rs; } /* * Listens on the socket */ int rudp_listen(int fd, void *arg) { rudp_socket_t rs; for (rs = rs_head; rs != NULL; rs = rs->next) { if (rs->sockfd == fd) break; } if (rs == NULL) { return -1; } int (*handler)(rudp_socket_t,struct sockaddr_in *, char *, int); /* client_addr.sin_family = AF_INET; client_addr.sin_addr.s_addr = htonl(INADDR_ANY); client_addr.sin_port = htons(0); */ unsigned int clientlen = sizeof(struct sockaddr); struct sockaddr client_sockaddr; int bufsize = RUDP_MAXPKTSIZE + sizeof (struct rudp_hdr); int msglen = 0; char message[bufsize]; memset(message, 0, bufsize); msglen =recvfrom(rs->sockfd, message, bufsize, 0, & client_sockaddr, &clientlen); if (msglen < 0) { perror("rudp_listen: recvfrom"); return -1; } struct sockaddr_in client_addr; memcpy(&client_addr, &client_sockaddr, clientlen); if (ntohs(client_addr.sin_port) == 0) { perror("rudp_listen: recvfrom port 0"); return -1; } //printf("received from port: %d\n",ntohs(client_addr.sin_port)); peer_t p = find_peer(&(rs->peers), &client_addr); if (p == NULL) { return -1; } //printf("peer: %d\n", ntohs(p->sa->sin_port)); if (msglen < 0) { perror("rudp_recvfrom: recvfrom"); return -1; } else if (msglen < (sizeof (struct rudp_hdr))) { fprintf(stderr, "rudp_recvfrom: error receiving packet"); return -1; } structrudp_hdr *msgheader = malloc(sizeof (struct rudp_hdr)); if (msgheader == NULL) { perror("rudp_recvfrom: malloc"); return -1; } memcpy(msgheader, message, sizeof (struct rudp_hdr)); //printf("status=%d sn=%d\n", p->status, p->sn); //printf("message from port %d, type=%d seqno=%d\n", ntohs(p->sa->sin_port), msgheader->type, msgheader->seqno); struct rudp_hdr *replyheader = malloc(sizeof (structrudp_hdr)); if (replyheader == NULL) { perror("rudp_recvfrom: malloc"); return -1; } replyheader->version = RUDP_VERSION; switch (p->status) { case PEER_STATUS_INIT: if (msgheader->type == RUDP_SYN) { p->status = PEER_STATUS_ACTIVE; p->sn = msgheader->seqno + 1; replyheader->seqno = msgheader->seqno + 1; replyheader->type = RUDP_ACK; sendto(fd, replyheader, sizeof (struct rudp_hdr), 0, (struct sockaddr*) & client_addr, clientlen); //printf("ACK sent. Turns active\n"); } break; case PEER_STATUS_PASSIVE: if (msgheader->type == RUDP_ACK && msgheader->seqno == 1) { p->status = PEER_STATUS_ACTIVE; packet_t pkt; for (pkt = p->packets; pkt != NULL; pkt = pkt->next) { if (pkt->header->seqno == msgheader->seqno - 1) { pkt->status = ACKED; //printf("syn packet no. %d acked\n", pkt->header->seqno); break; } } //p->sn = 1; p->sb = 1; p->sm = RUDP_WINDOW; } break; case PEER_STATUS_ACTIVE: switch (msgheader->type) { case RUDP_ACK: //printf("sb: %d sm: %d\n", p->sb, p->sm); if (msgheader->seqno >= p->sb) { packet_t pkt; for (pkt = p->packets; pkt != NULL; pkt = pkt->next) { if (pkt->header->seqno == msgheader->seqno - 1) { pkt->status = ACKED; //printf("data packet no. %d acked\n", pkt->header->seqno); break; } } p->sm += msgheader->seqno - p->sb; p->sb = msgheader->seqno; } break; case RUDP_DATA: #ifdef DROP srand(time(0)); if (rand() % DROP == 0) { printf("packet dropped\n"); break; } #endif if (msgheader->seqno == p->sn) { p->sn = msgheader->seqno + 1; replyheader->seqno = msgheader->seqno + 1; replyheader->type = RUDP_ACK; handler = malloc(sizeof (int (*)())); if (handler == NULL) { perror("rudp_listen: malloc"); return -1; } handler = (int (*)(rudp_socket_t, struct sockaddr_in*, char *, int))arg; void *data; data = malloc(msglen - sizeof (struct rudp_hdr)); if (data == NULL) { perror("rudp_listen: malloc"); return -1; } memcpy(data, message + sizeof (struct rudp_hdr), msglen - sizeof (struct rudp_hdr)); handler(rs, &client_addr, data, msglen - sizeof (struct rudp_hdr)); sendto(fd, replyheader, sizeof (struct rudp_hdr), 0, (struct sockaddr*) & client_addr, clientlen); } break; case RUDP_SYN: p->status = PEER_STATUS_ACTIVE; p->sn = msgheader->seqno + 1; replyheader->seqno = msgheader->seqno + 1; replyheader->type = RUDP_ACK; sendto(fd, replyheader, sizeof (struct rudp_hdr), 0, (struct sockaddr*) & client_addr, clientlen); break; case RUDP_FIN: p->status = PEER_STATUS_CLOSED; p->sn = msgheader->seqno + 1; replyheader->seqno = msgheader->seqno + 1; replyheader->type = RUDP_ACK; sendto(fd, replyheader, sizeof (struct rudp_hdr), 0, (struct sockaddr*) & client_addr, clientlen); break; default: fprintf(stderr, "rudp_listen: invalid RUDP type %d\n", msgheader->type); break; } break; case PEER_STATUS_CLOSING: if (msgheader->type == RUDP_ACK && msgheader->seqno == p->sn + 1) { p->status = PEER_STATUS_CLOSED; //printf("peer closed\n"); } break; case PEER_STATUS_CLOSED: if (msgheader->type == RUDP_FIN) { p->status = PEER_STATUS_CLOSED; p->sn = msgheader->seqno + 1; replyheader->seqno = msgheader->seqno + 1; replyheader->type = RUDP_ACK; sendto(fd, replyheader, sizeof (struct rudp_hdr), 0, (struct sockaddr*) & client_addr, clientlen); } /* if (msgheader->type == RUDP_SYN) { p->status = PEER_STATUS_ACTIVE; p->sn = msgheader->seqno + 1; replyheader->seqno = msgheader->seqno + 1; replyheader->type = RUDP_ACK; sendto(fd, replyheader, sizeof (struct rudp_hdr), 0, (struct sockaddr*) & client_addr, clientlen); } else if (msgheader->type == RUDP_FIN) { p->status = PEER_STATUS_CLOSED; p->sn = msgheader->seqno + 1; replyheader->seqno = msgheader->seqno + 1; replyheader->type = RUDP_ACK; sendto(fd, replyheader, sizeof (struct rudp_hdr), 0, (struct sockaddr*) & client_addr, clientlen); } */ break; default: fprintf(stderr, "rudp_listen: invalid peer status %d\n", p->status); break; } return 0; } /* * Keep checking if there are packets to be sent out */ int rudp_send(int fd, void *arg) { event_timeout_delete(rudp_send, arg); struct timeval now, interval, t; gettimeofday(&now, NULL); interval.tv_sec = 0; interval.tv_usec = RUDP_CHECK_INTERVAL; timeradd(&now, &interval, &t); rudp_socket_t rs; peer_t p; packet_t pkt; void *msg; int len = sizeof (struct rudp_hdr); //int rsc = 0; if (rs_head == NULL) { return 0; } for (rs = rs_head; rs != NULL; rs = rs->next) { //printf("rudp socket count: %d\n", ++rsc); for (p = rs->peers; p != NULL; p = p->next) { if (p->status == PEER_STATUS_CLOSED) { if (remove_peer(&(rs->peers), p) < 0) { perror("rudp_send: remove_peer"); return -1; } else { event_timeout(t, rudp_send, NULL, "rudp_send"); } return 0; } else if (p->status != PEER_STATUS_ACTIVE) { event_timeout(t, rudp_send, NULL, "rudp_send"); return 0; } //int pc = 0; for (pkt = p->packets; pkt != NULL; pkt = pkt->next) { //printf("pakcet %d: seq number %d status %d\n", ++pc, pkt->header->seqno, pkt->status); if (pkt->status == ACKED) { if (remove_packet(&(p->packets), pkt) == -1) { return -1; } event_timeout(t, rudp_send, NULL, "rudp_send"); return 0; } if ((pkt->status == IN_QUEUE || pkt->status == TIMEOUT) && pkt->header->seqno >= p->sb && pkt->header->seqno <= p->sm) { if (pkt->header->type == RUDP_FIN) { p->status = PEER_STATUS_CLOSING; } len = sizeof (struct rudp_hdr) + pkt->datalen; msg = malloc(len); if (msg == NULL) { perror("rudp_send: malloc"); return -1; } memcpy(msg, pkt->header, sizeof (struct rudp_hdr)); memcpy(msg + sizeof (struct rudp_hdr), pkt->data, pkt->datalen); sendto(rs->sockfd, msg, len, 0, (struct sockaddr*) p->sa, sizeof (struct sockaddr)); pkt->status = SENT; pkt->trans_count++; struct timeval now, interval, t; gettimeofday(&now, NULL); if (RUDP_TIMEOUT >= 1000) { interval.tv_sec = RUDP_TIMEOUT / 1000; interval.tv_usec = 0; } else { interval.tv_sec = 0; interval.tv_usec = RUDP_TIMEOUT * 1000; } timeradd(&now, &interval, &t); event_timeout(t, rudp_timeout, pkt, "rudp_timeout"); } } } } event_timeout(t, rudp_send, NULL, "rudp_send"); return 0; } int rudp_timeout(int a, void *arg) { packet_t pkt = (packet_t) arg; event_timeout_delete(rudp_timeout, pkt); if (pkt->status != ACKED) { //printf("Timeout: %d\n", pkt->header->seqno); pkt->status = TIMEOUT; if (pkt->trans_count >= RUDP_MAXRETRANS) pkt->status = FAILED; } return 0; } /* *rudp_close: Close socket */ int rudp_close(rudp_socket_t rsocket) { struct timeval now, interval, t; gettimeofday(&now, NULL); interval.tv_sec = 0; interval.tv_usec = RUDP_CHECK_INTERVAL; timeradd(&now, &interval, &t); event_timeout(t, rudp_close_session, rsocket, "rudp_close_socket"); return 0; /* peer_t p; packet_t pkt; struct rudp_hdr *hdr; hdr = malloc(sizeof (struct rudp_hdr)); if (hdr == NULL) { perror("rudp_sendto: malloc"); return -1; } pkt = malloc(sizeof (struct packet)); if (pkt == NULL) { perror("rudp_sendto: malloc"); return -1; } for (p = rsocket->peers; p != NULL; p = p->next) { hdr->version = RUDP_VERSION; hdr->type = RUDP_FIN; hdr->seqno = p->sn++; pkt->data = NULL; pkt->datalen = 0; pkt->header = hdr; pkt->next = NULL; pkt->trans_count = 0; pkt->status = IN_QUEUE; if (add_packet(&p->packets, &pkt) < 0) { perror("rudp_sendto: add_packet"); return -1; } } return 0; */ } int rudp_close_session(int fd, void *arg) { event_timeout_delete(rudp_close_session, arg); rudp_socket_t rs = (rudp_socket_t) arg; peer_t p; //printf("closing rudp socket %d\n", rs->sockfd); //printf("peer: %p\n", rs->peers); if (rs->peers == NULL) { //printf("peer null\n"); event_fd_delete(rudp_listen, rs); close(rs->sockfd); rudp_socket_t r, *rr; rr = &rs_head; for (r = rs_head; r != NULL; r = r->next) { if (r == rs) { *rr = r->next; free(r); return 0; } rr = &r->next; } return -1; } //printf("peers not null\n"); for (p = rs->peers; p != NULL; p = p->next) { //check if there are still packets to be sent if (p->packets != NULL) { struct timeval now, interval, t; gettimeofday(&now, NULL); interval.tv_sec = 0; interval.tv_usec = RUDP_CHECK_INTERVAL; timeradd(&now, &interval, &t); event_timeout(t, rudp_close_session, arg, "rudp_close_socket"); return 0; } //printf("no packets in this peer, status %d\n", p->status); if (p->status != PEER_STATUS_CLOSED) { p->status = PEER_STATUS_CLOSING; struct rudp_hdr header; header.seqno = p->sn; header.type = RUDP_FIN; header.version = RUDP_VERSION; sendto(rs->sockfd, &header, sizeof (struct rudp_hdr), 0, (struct sockaddr*) p->sa, sizeof (struct sockaddr_in)); struct timeval now, interval, t; gettimeofday(&now, NULL); if (RUDP_TIMEOUT >= 1000) { interval.tv_sec = RUDP_TIMEOUT / 1000; interval.tv_usec = 0; } else { interval.tv_sec = 0; interval.tv_usec = RUDP_TIMEOUT * 1000; } timeradd(&now, &interval, &t); event_timeout(t, rudp_close_session, arg, "rudp_close_socket"); //printf("FIN sent, check again 2s later\n"); return 0; } //printf("peer status closed\n"); if (remove_peer(&(rs->peers), p) < 0) { perror("rudp_close_session: remove_peer"); return -1; } else { //printf("peer successfully removed\n"); struct timeval now, interval, t; gettimeofday(&now, NULL); interval.tv_sec = 0; interval.tv_usec = RUDP_CHECK_INTERVAL; timeradd(&now, &interval, &t); event_timeout(t, rudp_close_session, arg, "rudp_close_socket"); return 0; } } return 0; } /* *rudp_recvfrom_handler: Register receive callback function */ int rudp_recvfrom_handler(rudp_socket_t rsocket, int (*handler)(rudp_socket_t, struct sockaddr_in *, char *, int)) { event_fd(rsocket->sockfd, rudp_listen, handler, "rudp_listen"); event_fd_delete(rudp_listen, rsocket); return 0; } /* *rudp_event_handler: Register event handler callback function */ int rudp_event_handler(rudp_socket_t rsocket, int (*handler)(rudp_socket_t, rudp_event_t, struct sockaddr_in *)) { struct timeval now, interval, t; gettimeofday(&now, NULL); interval.tv_sec = 0; interval.tv_usec = RUDP_CHECK_INTERVAL; timeradd(&now, &interval, &t); event_timeout(t, rudp_check_status, handler, "rudp_check_status"); return 0; } int rudp_check_status(int fd, void * arg) { event_timeout_delete(rudp_check_status, arg); int (*handler)(rudp_socket_t, rudp_event_t, struct sockaddr_in *); handler = (int (*)(rudp_socket_t, rudp_event_t, struct sockaddr_in *))arg; rudp_socket_t rs; peer_t p; packet_t pkt; for (rs = rs_head; rs != NULL; rs = rs->next) { for (p = rs->peers; p != NULL; p = p->next) { if (p->status == PEER_STATUS_CLOSED) { handler(rs, RUDP_EVENT_CLOSED, p->sa); if (remove_peer(&(rs->peers), p) < 0) return -1; return 0; } for (pkt = p->packets; pkt != NULL; pkt = pkt->next) { if (pkt->status == FAILED) { handler(rs, RUDP_EVENT_TIMEOUT, p->sa); if (remove_peer(&(rs->peers), p) < 0) return -1; return 0; } } } } struct timeval now, interval, t; gettimeofday(&now, NULL); interval.tv_sec = 0; interval.tv_usec = RUDP_CHECK_INTERVAL; timeradd(&now, &interval, &t); event_timeout(t, rudp_check_status, handler, "rudp_check_status"); return 0; } /* * rudp_sendto: Send a block of data to the receiver. */ int rudp_sendto(rudp_socket_t rsocket, void* data, int len, struct sockaddr_in* to) { peer_t p; packet_t pkt; struct rudp_hdr *hdr; hdr = malloc(sizeof (struct rudp_hdr)); if (hdr == NULL) { perror("rudp_sendto: malloc"); return -1; } pkt = malloc(sizeof (struct packet)); if (pkt == NULL) { perror("rudp_sendto: malloc"); return -1; } p = find_peer(&(rsocket->peers), to); if (p == NULL) { perror("rudp_sendto: find_peer"); return -1; } if (p->status == PEER_STATUS_INIT) { rudp_setup_session(0, p); } hdr = malloc(sizeof (struct rudp_hdr)); if (hdr == NULL) { perror("rudp_sendto: malloc"); return -1; } pkt = malloc(sizeof (struct packet)); if (pkt == NULL) { perror("rudp_sendto: malloc"); return -1; } hdr->version = RUDP_VERSION; hdr->type = RUDP_DATA; hdr->seqno = p->sn++; pkt->data = malloc(len); if (pkt->data == NULL) { perror("rudp_sendto: malloc"); return -1; } memcpy(pkt->data, data, len); pkt->datalen = len; pkt->header = hdr; pkt->next = NULL; pkt->trans_count = 0; pkt->status = IN_QUEUE; //printf("adding packet %d to %d\n", pkt->header->seqno, ntohs(p->sa->sin_port)); if (add_packet(&p->packets, &pkt) < 0) { perror("rudp_sendto: add_packet"); return -1; } return 0; } int rudp_setup_session(int fd, void *arg) { event_timeout_delete(rudp_setup_session, arg); peer_t p = (peer_t) arg; if (p == NULL) { perror("rudp_setup_session: error finding peer"); return -1; } int sockfd; rudp_socket_t rs; peer_t pp; int flag = 0; for (rs = rs_head; rs != NULL; rs = rs->next) { for (pp = rs->peers; pp != NULL; pp = pp->next) { if (pp == p) { sockfd = rs->sockfd; flag = 1; break; } } if (flag == 1) break; } struct rudp_hdr header; header.seqno = p->sn++; header.type = RUDP_SYN; header.version = RUDP_VERSION; sendto(sockfd, &header, sizeof (struct rudp_hdr), 0, (struct sockaddr*) p->sa, sizeof (struct sockaddr_in)); p->status = PEER_STATUS_PASSIVE; struct timeval now, interval, t; gettimeofday(&now, NULL); if (RUDP_TIMEOUT >= 1000) { interval.tv_sec = RUDP_TIMEOUT / 1000; interval.tv_usec = 0; } else { interval.tv_sec = 0; interval.tv_usec = RUDP_TIMEOUT * 1000; } timeradd(&now, &interval, &t); event_timeout(t, rudp_session_check, arg, "rudp_timeout"); gettimeofday(&now, NULL); interval.tv_sec = 0; interval.tv_usec = RUDP_CHECK_INTERVAL; timeradd(&now, &interval, &t); event_timeout(t, rudp_send, NULL, "rudp_send"); return 0; } int rudp_session_check(int fd, void *arg) { event_timeout_delete(rudp_session_check, arg); peer_t p = (peer_t) arg; if (p == NULL) { perror("rudp_setup_session: error finding peer"); return -1; } if (p->status == PEER_STATUS_PASSIVE) { struct timeval now, interval, t; gettimeofday(&now, NULL); interval.tv_usec = 0; interval.tv_sec = 0; timeradd(&now, &interval, &t); event_timeout(t, rudp_setup_session, arg, "rudp_setup_session"); } return 0; }
A linked list of all RUDP sockets is maintained. When rudp_socket() is called, an RUDP socket is created and added to the linked list. An RUDP socket keeps a record of the pees/sessions it talks with. When RUDP receives a packet from an unknown socket address, or when RUDP receives a send packet request to an unknown socket address, a new session is created. And for each session, a linked list of all buffered packets is kept.
Leave a CommentWhen rudp_sendto() is called, the protocol first check if there exists a session between the sender and receiver. If not, the protocol will try to setup a session by sending RUDP_SYN messages. And the packet the application wants to send will be buffered in the created session. After an RUDP_ACK message is received, the server side socket start sending out packets. Go back N protocol is used to control the sending process. After the protocol receives a rudp_close() signal, it will first check whether there are still active sessions and packets in the sending buffer. If not, the protocol will send out RUDP_FIN messages and after receiving RUDP_ACKs, the session is torn down.
Leave a CommentRUDP is a protocol that ensures transfer reliability with UDP. A sliding window protocol (Go back N) is used to realize reliability. Using RUDP, applications can send and receive data packets without worrying about lost packets.
The lines in red signifies state change for RUDP clients (receiver side); while the black lines signifies state change for RUDP servers (sender side).
Leave a CommentThis is done using JMF (Java Media Framework). Voice data is read from a file using `MediaLocator’. It is used as the data source for a `Processor’. The `Processor’ specifies and converts the audio data to a certain format and then output the converted data into a `DataSink’. The `DataSink’ then transfers the stream to its destination address and port.
Leave a CommentA SessionManager' is used to manage all the sessions. The
SessionManager’ keeps a list of sessions. When it receives data, it will first check which session the data belongs to. Then the data is given to the corresponding session. If it does not belong to any session in the list, a new session will be created and added to the session list.
The basic code looks like this:
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author Daoyuan */ public class SessionManager extends Thread { String user; String host; int port; String voiceFile; String defaultVoice; boolean listening = true; public static ArrayList sessionList; DatagramSocket serverSocket = null; public SessionManager(String user, String host, int port, String voiceFile, String defaultVoice) { this.user = user; this.host = host; this.port = port; this.voiceFile = voiceFile; this.defaultVoice = defaultVoice; sessionList = new ArrayList(); try { serverSocket = new DatagramSocket(port); } catch (SocketException ex) { Logger.getLogger(SessionManager.class.getName()).log(Level.SEVERE, null, ex); System.out.println("Unable to listen on port " + port); } } @Override public void run() { byte[] receiveData = newbyte[2048]; new Thread() { @Override public void run() { while (true) { try { Thread.sleep(5); } catch (InterruptedException ex) { Logger.getLogger(SessionManager.class.getName()).log(Level.SEVERE, null, ex); } if (sessionList.size() != 0) { for (int i= 0; i < sessionList.size(); i++) { if (sessionList.get(i).status.equals("destroyed")) { sessionList.remove(i); } } } } } }.start(); while (listening) { DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); try { serverSocket.receive(receivePacket); } catch (IOException ex) { Logger.getLogger(SessionManager.class.getName()).log(Level.SEVERE, null, ex); } if (isNewSession(receivePacket)) { System.out.println("New session created!"); } } serverSocket.close(); } public void stopListening() { listening = false; } private boolean isNewSession(DatagramPacket receivePacket) { InetAddress IPAddress = receivePacket.getAddress(); int remotePort = receivePacket.getPort(); String sessionName = IPAddress + ":" + remotePort; if (sessionList.size() == 0) { Session s = new Session(this.serverSocket, IPAddress, remotePort, voiceFile, defaultVoice, user); s.setName(sessionName); s.requests.add(receivePacket); sessionList.add(s); s.start(); return true; } else { for (int i = 0; i < sessionList.size(); i++) { if (sessionList.get(i).getName().equals(sessionName)) { sessionList.get(i).requests.add(receivePacket); return false; } } Session s = newSession(this.serverSocket, IPAddress, remotePort, voiceFile, defaultVoice, user); s.setName(sessionName); s.requests.add(receivePacket); sessionList.add(s); s.start(); return true; } } }Leave a Comment
Each session has a ‘status’, it can be ‘new’, ‘establishing’, ‘cancelling’, ‘established’, ‘tearingdown’ and ‘destroyed’.
When a new session is created, its status is ‘new’.
When an ‘INVITE’ is received, it sends out an ‘OK’ message and change its status to ‘establishing’.
After receiving an ‘ACK’ message the status will be changed to ‘established’.
Then begins the transferring of voice data using RTP.
When the sending finishes the status will become ‘tearingdown’.
A ‘BYE’ message is also sent to the client.
The status becomes ‘destroyed’ after getting ‘OK’ from the client.
When a ‘CANCEL’ message is received, the status becomes ‘cancelling’.
Then it sends back ‘OK’ and ‘Request Terminated’ messages.
After received an ‘ACK’, the status becomes ‘destroyed’.
The thread is as follows:
@Override public void run() { while (true) { if (requests.size() == 0) { try { Thread.sleep(10); } catch (InterruptedException ex) { Logger.getLogger(Session.class.getName()).log(Level.SEVERE, null, ex); } } else { final DatagramPacket packet = requests.get(0); final String request = new String(packet.getData()); System.err.println(request); sipRequest = new SIPRequest(request); if (request.toUpperCase().startsWith("INVITE")) { System.out.println("Got INVITE"); if (!status.equals("new")) { requests.remove(0); continue; } String requestLine = request.substring(6).trim(); String uri = requestLine.substring(0, requestLine.indexOf(' ')); //System.out.println(uri); String usr = ""; if (uri.toUpperCase().startsWith("SIP:")) { usr = uri.substring(4, uri.indexOf('@')); } else { usr = uri.substring(0, uri.indexOf('@')); } if (!usr.equalsIgnoreCase(user)) { sendUserNotFound(sipRequest); status = "tearingdown"; System.out.println("Status: " + status); continue; } sendTrying(sipRequest); sendRinging(sipRequest); final String rtpport = request.substring(request.indexOf("m=audio") + 8, request.indexOf("m=audio") + 13); final String sdp = getSDP(request); new Thread() { @Override public void run() { File file = new File("wav/" + voiceFile); if (file.exists()) { locator = new MediaLocator("file:/" + file.getAbsolutePath()); } else { System.out.println("Using default voice file!"); locator = new MediaLocator("file:/" + file.getAbsolutePath()); } transmitter = new Transmitter(locator, packet.getAddress().toString().substring(1), rtpport); transmitter.prepare(); } }.start(); new Thread() { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException ex) { Logger.getLogger(Session.class.getName()).log(Level.SEVERE, null, ex); } if (status.equals("establishing")) { sendOK(sipRequest, sdp, rtpport); } else { try { transmitter.stop(); } catch (NullPointerException ex) { Logger.getLogger(Session.class.getName()).log(Level.SEVERE, null, ex); System.out.println("Transmitter already stopped!"); } } } }.start(); requests.remove(0); status = "establishing"; System.out.println("Status: " + status); } else if (request.toUpperCase().startsWith("ACK")) { System.out.println("Got ACK"); //sendOK(sipRequest); requests.remove(0); if (status.equals("establishing")) { status = "established"; System.out.println("Status: " + status); new Thread() { @Override public void run() { transmitter.start(); long duration = new VoiceInfo(locator).getDuration(); try { Thread.sleep(duration); } catch (InterruptedException ex) { Logger.getLogger(Session.class.getName()).log(Level.SEVERE, null, ex); } try { transmitter.stop(); } catch (NullPointerException ex) { Logger.getLogger(Session.class.getName()).log(Level.SEVERE, null, ex); System.out.println("Transmitter already stopped!"); } if (!status.equals("tearingdown") && !status.equals("destroyed")) { sendBye(sipRequest); status = "tearingdown"; System.out.println("Status: " + status); } } }.start(); } else if (status.equals("tearingdown")) { status = "destroyed"; System.out.println("Status: " + status); break; } else if (status.equals("cancelling")) { status = "destroyed"; System.out.println("Status: " + status); break; } } else if (request.toUpperCase().startsWith("BYE")) { System.out.println("Got BYE"); sendOKWithoutSDP(sipRequest); requests.remove(0); try { transmitter.stop(); } catch (NullPointerException ex) { Logger.getLogger(Session.class.getName()).log(Level.SEVERE, null, ex); System.out.println("Transmitter already stopped!"); } status = "destroyed"; System.out.println("Status: " + status); break; } else if (request.toUpperCase().startsWith("SIP/2.0 200")) { requests.remove(0); System.out.println("Got OK"); if (status.equals("tearingdown")) { status = "destroyed"; System.out.println("Status: " + status); break; } } else if (request.toUpperCase().startsWith("CANCEL")) { requests.remove(0); System.out.println("Got CANCEL"); status = "cancelling"; System.out.println("Status: " + status); sendOKWithoutSDP(sipRequest); sendTerminated(sipRequest); } else { requests.remove(0); } } } }Leave a Comment