Main Page | Class List | File List | Class Members | File Members

tcpproxy.c

Go to the documentation of this file.
00001 /* TCP Proxy server.
00002  *
00003  */
00004 
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <stdarg.h>
00008 #include <assert.h>
00009 #include <string.h>
00010 #include <libgen.h>
00011 #include <linux/netfilter.h>
00012 #include "libipq.h"
00013 #include <linux/ip.h>
00014 #include <arpa/inet.h>
00015 #include <signal.h>
00016 #include <pthread.h>
00017 
00018 #include "misc.h"
00019 #include "tcp.h"
00020 #include "scheduler.h"
00021 #include "tcptimer.h"
00022 #include "tcpproxy.h"
00023 
00024 #define IPQ_BUF_SIZE 10240
00025 
00026 /*----------------------------------------------------------------------
00027  * Global variables
00028  *----------------------------------------------------------------------
00029  */
00030 static struct ipq_handle *qh;   /* IP packet queue handle. */
00031 static __u32 mob_ip;            /* IP address of mobile host.*/
00032 static pthread_t sched_thread;  /* Scheduler thread. */
00033 static pthread_t timer_thread;  /* TCP timer thread. */
00034 
00035 volatile sig_atomic_t request_exit = 0;  /* Flag to request exit. */
00036 pthread_t main_thread;                   /* Main thread. */
00037 
00038 /*----------------------------------------------------------------------
00039  * alloc_packet_data -  allocates data for a packet.
00040  *----------------------------------------------------------------------
00041  */
00042 inline Tpacket_data *alloc_packet_data(ipq_packet_msg_t *p)
00043 {
00044     Tpacket_data *pd;
00045     pd = (Tpacket_data*) xmalloc(sizeof(Tpacket_data));
00046     pd->payload = (unsigned char*) xmalloc(p->data_len);
00047     
00048     /* Copy data into packet_data structure. */
00049     memcpy(&pd->ipq_pm, p, sizeof(ipq_packet_msg_t));
00050     memcpy(pd->payload, p->payload, p->data_len);
00051     pd->ip = (struct iphdr*) pd->payload;
00052     pd->trans.hdr = (pd->payload + (pd->ip->ihl*4));
00053 
00054     return pd;
00055 }
00056 
00057 /*----------------------------------------------------------------------
00058  * dealloc_packet_data -  deallocates data for a packet.
00059  *----------------------------------------------------------------------
00060  */
00061 inline void dealloc_packet_data(Tpacket_data *pd)
00062 {
00063     assert(pd != NULL);
00064     xfree(pd->payload);
00065     xfree(pd);
00066 }
00067 
00068 /*----------------------------------------------------------------------
00069  * ip_chksum -  computes checksum for ip header
00070  *              takes ipq_packet_msg and length of header in 16 bit words
00071  *              when called on a packet that contains a checksum, will
00072  *              return zero if the checksum is valid, nonzero otherwise.
00073  *----------------------------------------------------------------------
00074  */
00075 unsigned short ip_chksum(ipq_packet_msg_t *p, unsigned int words)
00076 {
00077     unsigned short *buf = (unsigned short*)p->payload;
00078     unsigned long chksum;
00079     
00080     for(chksum=0; words>0; words--)
00081         chksum += *buf++;
00082 
00083     chksum = (chksum >> 16) + (chksum & 0xffff);  /* Add carry. */
00084     chksum += (chksum >> 16);                     /* And again. */
00085     chksum = ~chksum & 0xffff;  /* Take ones complement and mask off high bits. */
00086 
00087     return chksum;
00088 }
00089 
00090 
00091 /*----------------------------------------------------------------------
00092  * handle_icmp -  handles ICMP packets.
00093  *----------------------------------------------------------------------
00094  */
00095 int handle_icmp(Tpacket_data *pd)
00096 {
00097     queue_hipri(pd);
00098     return 0;
00099 }
00100 
00101 /*----------------------------------------------------------------------
00102  * handle_other -  handles packets that aren't ICMP or TCP (e.g. UDP).
00103  *----------------------------------------------------------------------
00104  */
00105 int handle_other(Tpacket_data *pd) 
00106 {
00107     queue_lowpri(pd);
00108     return 0;
00109 }
00110 
00111 /*----------------------------------------------------------------------
00112  * handle_packet -  handle basic (IP) packets; calls other protocol
00113  *                  specific handlers.
00114  *----------------------------------------------------------------------
00115  */
00116 int handle_packet(ipq_packet_msg_t *p)
00117 {
00118     Tpacket_data *pd;
00119     struct iphdr *ip;
00120     int ret;
00121     
00122     if(p->data_len == 0) {
00123         EPRINT("handle_packet: message does not contain any data.\n");
00124         return -1;
00125     }
00126     
00127     ip = (struct iphdr*) p->payload;
00128     if(p->data_len < ip->ihl*4) {
00129         IPRINT("handle_packet: ip hlen value too big for packet length: %d\n", ip->ihl);
00130         return -1;
00131     }
00132 
00133     if(p->data_len != ntohs(ip->tot_len)) {
00134         IPRINT("handle_packet: ip packet has incorrect length field: %d\n",
00135                ntohs(ip->tot_len));
00136         return -1;
00137     }
00138 
00139     /* The kernel may throw away packets with bad IP checksums before they get to us,
00140      * but we'll check it too, just to make sure.
00141      */
00142     if(ip_chksum(p, ip->ihl*2)) {
00143         DPRINT("handle_packet: bad ip checksum: %u\n", ntohs(ip->check));
00144         return -1;
00145     }
00146 
00147     pd = alloc_packet_data(p);
00148     
00149     if(DEBUG) {
00150         int frag = ntohs(pd->ip->frag_off);
00151         IPRINT("\n");
00152         /*IPRINT("id: %lu, mark: %lu, timestamp: %ld, indev: %s, datalen: %d\n",
00153           pd->ipq_pm.packet_id, pd->ipq_pm.mark, pd->ipq_pm.timestamp_sec,
00154           pd->ipq_pm.indev_name, pd->ipq_pm.data_len);*/
00155         IPRINT("ip ver: %u, ihl: %u, tos: %u, id: %u, ttl: %u, frag: %c%c%c %u\n",
00156                pd->ip->version, pd->ip->ihl, pd->ip->tos, pd->ip->id,
00157                pd->ip->ttl, (frag&0x80?'R':'.'), (frag&0x4000?'D':'.'),
00158                (frag&0x2000?'M':'.'), (frag&0x1fff));
00159         IPRINT("ip len: %u, proto: %u, ", ntohs(pd->ip->tot_len), pd->ip->protocol);
00160         IPRINT("%s->", inet_ntoa(*(struct in_addr*)&(pd->ip->saddr)));
00161         IPRINT("%s\n", inet_ntoa(*(struct in_addr*)&(pd->ip->daddr)));
00162     }
00163 
00164     if(pd->ip->version != 4) {
00165         EPRINT("handle_packet: error: packet not IPv4.\n");
00166         exit(EXIT_ERR_WRONG_IP_VER);
00167     }
00168     
00169     /* Determine direction of packet. */
00170 
00171     if(pd->ip->daddr == mob_ip) {
00172         pd->dir = PACKET_DIR_IN;
00173     } else if(pd->ip->saddr == mob_ip) {
00174         pd->dir = PACKET_DIR_OUT;
00175     } else {
00176         EPRINT("handle_packet: neither src nor dst correspond to mobile ip - allowing through.\n");
00177         dealloc_packet_data(pd);
00178         ret = ipq_set_verdict(qh, p->packet_id, NF_ACCEPT, 0, 0);
00179         if (ret < 0) {
00180             EPRINT("handle_packet: error setting ipq verdict.\n");
00181             ipq_perror("handle_packet");
00182         }    
00183         return -1;
00184     }
00185 
00186     switch(pd->ip->protocol)
00187     {
00188     case 1: /* ICMP */
00189         handle_icmp(pd);
00190         break;
00191     case 6: /* TCP */
00192         handle_tcp(pd);
00193         break;
00194     default: /* The rest. */
00195         handle_other(pd);
00196         break;
00197     }
00198 
00199     ret = ipq_set_verdict(qh, p->packet_id, NF_DROP, 0, 0);
00200 
00201     if (ret < 0) {
00202         EPRINT("handle_packet: error setting ipq verdict.\n");
00203         ipq_perror("handle_packet");
00204     }    
00205     return 0;
00206 }
00207 
00208 /*----------------------------------------------------------------------
00209  * cleanup -  stop threads, and destroy ipq handle.
00210  *----------------------------------------------------------------------
00211  */
00212 void cleanup ()
00213 {
00214     IPRINT("Quiting.\n");
00215 
00216     if(!request_exit)
00217         request_exit = 1;
00218 
00219     pthread_cancel(timer_thread);
00220     pthread_cancel(sched_thread);
00221 
00222     if(ipq_destroy_handle(qh) == -1) {
00223         EPRINT("cleanup: error destroying ipq handle.\n");
00224         ipq_perror("cleanup");
00225         exit(EXIT_ERR_IPQ_DESTROY_HANDLE);      
00226     }
00227 }
00228 
00229 /*----------------------------------------------------------------------
00230  * signal_handler -  signal handing function
00231  *----------------------------------------------------------------------
00232  */
00233 void signal_handler (int signum)
00234 {
00235     //DPRINT("signal_handler: entered.\n");
00236     
00237     switch(signum)
00238     {
00239     case SIGTERM:
00240         DPRINT("\nReceived SIGTERM\n");
00241         break;
00242     case SIGINT:
00243         DPRINT("\nReceived SIGINT\n");
00244         break;
00245     case SIGHUP:
00246         DPRINT("\nReceived SIGHUP\n");
00247         break;
00248     default:
00249         EPRINT("\nsignal_handler: invalid signal received");
00250         break;
00251     }
00252 
00253     exit(request_exit);  /* Exit with return value from request_exit. */
00254 }
00255 
00256 /*----------------------------------------------------------------------
00257  * main -  starts everything rolling.
00258  *----------------------------------------------------------------------
00259  */
00260 int main(int argc, const char* argv[])
00261 {
00262     struct sigaction sact, soldact;
00263     pthread_attr_t thread_attr;
00264     /* Array of signums, last element must be zero. */
00265     int sigs [] = { SIGTERM, SIGINT, SIGHUP, 0};
00266     int i;
00267     char buf[IPQ_BUF_SIZE];
00268     ssize_t len;
00269     int mtype;
00270     int error;
00271     ipq_packet_msg_t *packet;
00272     struct in_addr mob_addr;
00273 
00274     main_thread = pthread_self();
00275 
00276     if(argc != 2) {
00277         printf("Invalid number of arguments.\n");
00278         printf("Usage: %s mobile_ip\n", argv[0]);
00279         exit(EXIT_ERR_USAGE);
00280     }
00281 
00282     if(inet_aton(argv[1], &mob_addr) == 0) {
00283         printf("Bad mobile IP address: %s\n", argv[1]);
00284         exit(EXIT_ERR_BAD_MOBILE_IP);
00285     }
00286     mob_ip = mob_addr.s_addr;
00287     DPRINT("main: starting proxy for mobile host '%s'.\n", argv[1]);
00288 
00289     if(pthread_attr_init(&thread_attr) ||
00290        pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED)) {
00291         EPRINT("main: error setting pthread attr.\n");
00292         exit(EXIT_ERR_PTHREAD_ATTR);
00293     }
00294 
00295     if(sigemptyset(&sact.sa_mask)) {
00296         EPRINT("main: error calling segemptyset.\n");
00297     }
00298     for(i=0; sigs[i] != 0; i++) {
00299         if(sigaddset(&sact.sa_mask, sigs[i])) {
00300             EPRINT("main: error calling segaddset.\n");     
00301         }
00302     }
00303 
00304     sact.sa_handler = signal_handler;
00305     sact.sa_flags = 0;
00306 
00307     for(i=0; sigs[i]; i++) {
00308         if(sigaction(sigs[i], &sact, &soldact)) {
00309             EPRINT("main: error setting signal handler.\n");
00310             exit(EXIT_ERR_SET_SIG_HANDLER);
00311         } else if(soldact.sa_handler == SIG_IGN) {
00312             sigaction(sigs[i], &soldact, NULL);
00313         }
00314     }
00315     
00316     //if(fork()) exit(0);
00317 
00318     qh = ipq_create_handle(0, PF_INET);
00319     if(!qh) {
00320         EPRINT("main: error creating netlink handle.\n");
00321         ipq_perror("main");
00322         exit(EXIT_ERR_IPQ_CREATE_HANDLE);
00323     }
00324 
00325     if(ipq_set_mode(qh, IPQ_COPY_PACKET, IPQ_BUF_SIZE) < 0) {
00326         EPRINT("main: error setting netlink mode.\n");
00327         ipq_perror("main");
00328         exit(EXIT_ERR_IPQ_SET_MODE);
00329     }
00330 
00331     atexit(cleanup);
00332 
00333     init_sched();
00334     atexit(cleanup_sched);
00335     init_timer();
00336     atexit(cleanup_timer);
00337     init_tcp();
00338     atexit(cleanup_tcp);
00339 
00340     if(pthread_create(&sched_thread, NULL, (void*)scheduler, &sact.sa_mask)) {
00341         EPRINT("main: error creating scheduler thread.\n");
00342         perror("main");
00343         exit(EXIT_ERR_CREATE_THREAD);
00344     }
00345 
00346     if(pthread_create(&timer_thread, NULL, (void*)tcp_timer, &sact.sa_mask)) {
00347         EPRINT("main: error creating TCP timer thread.\n");
00348         perror("main");
00349         exit(EXIT_ERR_CREATE_THREAD);
00350     }
00351 
00352     DPRINT("main: ready to receive packets.\n");
00353 
00354     while (!request_exit) {
00355         /* Perform blocking read from queue. */
00356         len = ipq_read(qh, buf, IPQ_BUF_SIZE, 0);
00357         //DPRINT("ipq_read len=%d\n", len);
00358         
00359         if(len <= 0) {
00360             EPRINT("main: error returned from ipq_read.\n");
00361             ipq_perror("main");
00362             //exit(EXIT_ERR_IPQ_READ);
00363         } else {
00364             mtype = ipq_message_type(buf);
00365             switch(mtype)
00366             {
00367             case IPQM_PACKET:
00368                 packet = ipq_get_packet(buf);
00369                 handle_packet(packet);
00370                 break;
00371             case NLMSG_ERROR:
00372                 error = ipq_get_msgerr(buf);
00373                 //EPRINT("main: error reading packet: %s\n",
00374                         //Rajiv strerror_r[error]);
00375                 exit(EXIT_ERR_IPQ_ERR_MESSAGE);
00376                 break;
00377             default:
00378                 EPRINT("main: invalid message type received.\n");
00379                 exit(EXIT_ERR_IPQ_MESSAGE_TYPE);
00380                 break;
00381             }
00382         }
00383     }
00384 
00385     exit(0);
00386 }

Generated on Sun May 14 13:36:52 2006 by  doxygen 1.4.2