source of highlighter
plain | download
    1 #include <errno.h>
    2 #include <stdio.h>
    3 #include <stdlib.h>
    4 #include <string.h>
    5 #include <unistd.h>
    6 #include <fcntl.h>
    7 #include <poller.h>
    8 #include <time.h>
    9 #include <sys/types.h>
   10 #include <sys/socket.h>
   11 #include <sys/ioctl.h>
   12 #include <netinet/in.h>
   13 #include <netinet/ip.h>
   14 #include <netinet/ip_icmp.h>
   15 #include <netinet/tcp.h>
   16 #include <netinet/udp.h>
   17 #include <arpa/inet.h>
   18 #include <linux/if.h>
   19 #include <linux/if_tun.h>
   20 #include <inttypes.h>
   21 
   22 int tunfd, poller;
   23 struct sockaddr_in socks_server;
   24 
   25 struct connection
   26 {
   27   int fd;
   28 #define TCPCON  0
   29 #define UDPCON  1
   30   unsigned int type : 1;
   31   int status : 4;
   32   unsigned int fin : 2;
   33   unsigned int reserved : 1;
   34 
   35   uint32_t seq, ack_seq, echo;
   36   uint16_t id, mss;
   37   char * buffer;
   38   size_t buflen;
   39   char orig[68];
   40   struct sockaddr_in local, remote;
   41   struct connection * prev, * next;
   42 } * first_connection = NULL;
   43 
   44 struct connection *
   45 find_connection (struct in_addr src, uint16_t srcport,
   46                  struct in_addr dst, uint16_t dstport, int type)
   47 {
   48   struct connection * now;
   49 
   50   for (now = first_connection; now != NULL; now = now->next)
   51     {
   52       if (((now->local.sin_addr.s_addr == src.s_addr
   53             && now->local.sin_port == srcport
   54             && now->remote.sin_addr.s_addr == dst.s_addr
   55             && now->remote.sin_port == dstport)
   56            || (now->remote.sin_addr.s_addr == src.s_addr
   57             && now->remote.sin_port == srcport
   58             && now->local.sin_addr.s_addr == dst.s_addr
   59             && now->local.sin_port == dstport))
   60           && (!type || type == now->type))
   61         return now;
   62     }
   63   return NULL;
   64 }
   65 
   66 void
   67 remove_connection (struct connection * conn)
   68 {
   69   if (conn->buffer != NULL)
   70     free (conn->buffer);
   71   if (conn->next != NULL)
   72     conn->next->prev = conn->prev;
   73   if (conn->prev != NULL)
   74     conn->prev->next = conn->next;
   75   if (conn == first_connection)
   76     first_connection = conn->next;
   77   free (conn);
   78 }
   79 
   80 #define Econnrefused    -1
   81 #define Enetunreach     -2
   82 #define Ehostunreach    -3
   83 #define Ettlexpired     -4
   84 
   85 int
   86 socks_connect ()
   87 {
   88   int sock;
   89   unsigned char buf[280];
   90 
   91   sock = socket (AF_INET, SOCK_STREAM, 0);
   92   if (sock < 0)
   93     return Enetunreach;
   94 
   95   if (connect (sock, (struct sockaddr *) &socks_server, sizeof (socks_server)))
   96     goto close_netunreach;
   97 
   98   buf[0] = 5;
   99   buf[1] = 1;
  100   buf[2] = 0;
  101 
  102   if (write (sock, buf, 3) < 3)
  103     goto close_netunreach;
  104 
  105   return sock;
  106 
  107 close_netunreach:
  108   close (sock);
  109   return Enetunreach;
  110 }
  111 
  112 int
  113 socks_connect2 (struct connection * conn)
  114 {
  115   unsigned char buf[280];
  116   size_t toread;
  117   int err;
  118 
  119   if (conn->status == 0)
  120     {
  121       if (read (conn->fd, buf, 2) < 2)
  122         goto close_netunreach;
  123 
  124       if (buf[0] != 0x05 && buf[1] != 0x00)
  125         goto close_netunreach;
  126 
  127       buf[0] = 5;
  128       buf[1] = conn->type == TCPCON ? 1 : 3;
  129       buf[2] = 0;
  130       buf[3] = 1;
  131       if (conn->type == TCPCON)
  132         {
  133           memcpy (buf+4, &conn->remote.sin_addr, 4);
  134           memcpy (buf+8, &conn->remote.sin_port, 2);
  135         }
  136       else
  137         memset (buf+4, 0, 6);
  138       if (write (conn->fd, buf, 10) < 10)
  139         goto close_netunreach;
  140 
  141       return 1;
  142     }
  143   else if (conn->status == 1)
  144     {
  145       if (read (conn->fd, buf, 5) < 5)
  146         goto close_netunreach;
  147 
  148       if (buf[0] != 5 || buf[2] != 0)
  149         goto close_netunreach;
  150 
  151       switch (buf[1])
  152         {
  153           case 0:
  154             err = 0;
  155             break;
  156           case 4:
  157             err = Ehostunreach;
  158             break;
  159           case 5:
  160             err = Econnrefused;
  161             break;
  162           case 6:
  163             err = Ettlexpired;
  164             break;
  165           default:
  166             err = Enetunreach;
  167         }
  168 
  169       if (err)
  170         {
  171           close (conn->fd);
  172           return err;
  173         }
  174 
  175       if (buf[3] == 1)
  176         toread = 6-1;
  177       else if (buf[3] == 3)
  178         toread = buf[4] + 2;
  179       else if (buf[3] == 4)
  180         toread = 18-1;
  181       else
  182         goto close_netunreach;
  183 
  184       if (read (conn->fd, buf, toread) < toread)
  185         goto close_netunreach;
  186 
  187       return 2;
  188     }
  189 
  190 close_netunreach:
  191   close (conn->fd);
  192   return Enetunreach;
  193 }
  194 
  195 int
  196 tun_alloc (char * dev)
  197 {
  198   struct ifreq ifr;
  199   int fd, err;
  200 
  201   if ((fd = open ("/dev/net/tun", O_RDWR)) < 0)
  202     return (-1);
  203 
  204   memset (&ifr, 0, sizeof (ifr));
  205   ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
  206   if (*dev)
  207     strncpy (ifr.ifr_name, dev, IFNAMSIZ);
  208 
  209   if ((err = ioctl (fd, TUNSETIFF, (void *) &ifr)) < 0)
  210     {
  211       close (fd);
  212       return err;
  213     }
  214   strcpy (dev, ifr.ifr_name);
  215 
  216   return fd;
  217 }
  218 
  219 static inline int16_t
  220 csum_add (int16_t sum, int16_t addend)
  221 {
  222   uint32_t res = (uint32_t) sum;
  223   res += (uint32_t) addend;
  224   return (int16_t) (res + (res < (uint32_t) addend));
  225 }
  226 
  227 static inline int16_t
  228 ip_tcpudp_csum (struct in_addr * src, struct in_addr * dst)
  229 {
  230   int16_t csum = 0;
  231   csum = csum_add (csum, ntohs (*((int16_t *) src)));
  232   csum = csum_add (csum, ntohs (*(((int16_t *) src)+1)));
  233   csum = csum_add (csum, ntohs (*((int16_t *) dst)));
  234   csum = csum_add (csum, ntohs (*(((int16_t *) dst)+1)));
  235   return csum;
  236 }
  237 
  238 void
  239 parse_tcp_opts (char * buf, size_t len, uint16_t * mss, uint8_t * wscale,
  240                 int * sack, uint32_t * timestamp, uint32_t * echo)
  241 {
  242   size_t now = 0;
  243 
  244   if (mss != NULL)
  245     *mss = 0;
  246   if (wscale != NULL)
  247     *wscale = 0;
  248   if (sack != NULL)
  249     *sack = 0;
  250   if (timestamp != NULL && echo != NULL)
  251     *timestamp = *echo = 0;
  252 
  253   while (now < len)
  254     {
  255       if (buf[now] == 0)
  256         break;
  257       else if (buf[now] == 1)
  258         now ++;
  259       else if (buf[now] == 2 && buf[now+1] == 4)
  260         {
  261           if (mss != NULL)
  262             *mss = (buf[now+2] << 8) | (buf[now+3] & 0xff);
  263           now += 4;
  264         }
  265       else if (buf[now] == 3 && buf[now+1] == 3)
  266         {
  267           if (wscale != NULL)
  268             *wscale = buf[now+2];
  269           now += 3;
  270         }
  271       else if (buf[now] == 4 && buf[now+1] == 2)
  272         {
  273           if (sack != NULL)
  274             *sack = 1;
  275           now += 2;
  276         }
  277       else if (buf[now] == 8 && buf[now+1] == 10)
  278         {
  279           if (timestamp != NULL && echo != NULL)
  280             {
  281               *timestamp = ntohl (*((uint32_t *) (buf + now + 2)));
  282               *echo = ntohl (*((uint32_t *) (buf + now + 6)));
  283             }
  284           now += 10;
  285         }
  286     }
  287 }
  288 
  289 size_t
  290 build_tcp (char * buf, int16_t csum, uint16_t source, uint16_t dest,
  291            uint32_t seq, uint32_t ack_seq, int syn, int ack, int psh, int rst,
  292            int fin, uint16_t window, uint16_t mss, uint8_t wscale, int sack,
  293            uint32_t timestamp, uint32_t echo, char * data, size_t len)
  294 {
  295   struct tcphdr * h = (struct tcphdr *) buf;
  296   size_t hlen = 20;
  297   int i;
  298 
  299   memset (buf, 0, hlen);
  300 
  301   h->source = htons (source);
  302   h->dest = htons (dest);
  303   h->seq = htonl (seq);
  304   h->ack_seq = htonl (ack_seq);
  305   if (syn)
  306     h->syn = 1;
  307   if (ack)
  308     h->ack = 1;
  309   if (psh)
  310     h->psh = 1;
  311   if (rst)
  312     h->rst = 1;
  313   if (fin)
  314     h->fin = 1;
  315   h->window = htons (window);
  316   h->urg_ptr = 0;
  317   if (mss)
  318     {
  319       buf[hlen++] = 2;
  320       buf[hlen++] = 4;
  321       buf[hlen++] = (mss >> 8) & 0xff;
  322       buf[hlen++] = mss & 0xff;
  323     }
  324   if (sack)
  325     {
  326       buf[hlen++] = 4;
  327       buf[hlen++] = 2;
  328     }
  329   if (timestamp)
  330     {
  331       buf[hlen++] = 8;
  332       buf[hlen++] = 10;
  333       *((uint32_t *) (buf + hlen)) = htonl (timestamp);
  334       *((uint32_t *) (buf + hlen + 4)) = htonl (echo);
  335       hlen += 8;
  336     }
  337   if (wscale)
  338     {
  339       if ((hlen >> 1) & 1)
  340         {
  341           buf[hlen++] = 1;
  342           buf[hlen++] = 1;
  343         }
  344       buf[hlen++] = 1;
  345       buf[hlen++] = 3;
  346       buf[hlen++] = 3;
  347       buf[hlen++] = wscale;
  348     }
  349   while (hlen % 4)
  350     buf[hlen++] = 1;
  351   h->doff = hlen/4;
  352   if (data != NULL && len > 0)
  353     memcpy (buf + hlen, data, len);
  354   csum = csum_add (csum, IPPROTO_TCP);
  355   csum = csum_add (csum, hlen+len);
  356   for (i = 0; i < hlen+len; i += 2)
  357     csum = csum_add (csum, ntohs (*(int16_t *) (buf + i)));
  358   if (len & 1)
  359     csum = csum_add (csum, buf[hlen+len-1] << 8);
  360   h->check = htons (~csum);
  361   return (hlen+len);
  362 }
  363 
  364 size_t
  365 build_udp (char * buf, int16_t csum, uint16_t source, uint16_t dest,
  366            char * data, size_t len)
  367 {
  368   struct udphdr * h = (struct udphdr *) buf;
  369   int i;
  370 
  371   h->source = htons (source);
  372   h->dest = htons (dest);
  373   h->len = htons (8+len);
  374   h->check = 0;
  375   csum = csum_add (csum, IPPROTO_UDP);
  376   csum = csum_add (csum, 8+len);
  377   for (i = 0; i < 8+len; i += 2)
  378     csum = csum_add (csum, ntohs (*(int16_t *) (buf + i)));
  379   if (len & 1)
  380     csum = csum_add (csum, buf[8+len-1] << 8);
  381   h->check = htons (~csum);
  382   return (8+len);
  383 }
  384 
  385 size_t
  386 build_icmp (char * buf, uint8_t type, uint8_t code, struct ip * orig)
  387 {
  388   struct icmphdr * h = (struct icmphdr *) buf;
  389   int16_t csum = 0;
  390   size_t origlen;
  391   int i;
  392 
  393   memset (buf, 0, 8);
  394 
  395   h->type = type;
  396   h->code = code;
  397   for (i = 0; i < 8; i += 2)
  398     csum = csum_add (csum, ntohs (*(int16_t *) (buf + i)));
  399   h->checksum = htons (~csum);
  400 
  401 #define MIN(a,b) ((a)<(b)?(a):(b))
  402   origlen = MIN(orig->ip_hl*4 + 8, orig->ip_len);
  403 
  404   if (orig != NULL)
  405     memcpy (buf+8, orig, origlen);
  406 
  407   return (8+origlen);
  408 }
  409 
  410 void
  411 build_ip (char * buf, uint16_t len, uint16_t id, uint16_t off, uint8_t ttl,
  412           uint8_t prot, struct in_addr src, struct in_addr dst)
  413 {
  414   struct ip * h = (struct ip *) buf;
  415   uint16_t csum = 0;
  416   int i;
  417 
  418   memset (buf, 0, 20);
  419 
  420   h->ip_v = 4;
  421   h->ip_hl = 5;
  422   h->ip_len = htons (len);
  423   h->ip_id = htons (id);
  424   h->ip_off = htons (off);
  425   h->ip_ttl = ttl;
  426   h->ip_p = prot;
  427   h->ip_src = src;
  428   h->ip_dst = dst;
  429   for (i = 0; i < 20; i += 2)
  430     csum = csum_add (csum, ntohs (*(int16_t *) (buf + i)));
  431   h->ip_sum = htons (~csum);
  432 }
  433 
  434 void
  435 polled (pollerdata_t data, pollerev_t events)
  436 {
  437   if (data.ptr == NULL)
  438     {
  439       unsigned char buf[65536];
  440       struct ip * iph;
  441 
  442       read (tunfd, buf, 65536);
  443       iph = (struct ip *) buf;
  444       if (iph->ip_v == 4)
  445         {
  446           struct connection * conn;
  447           char reply[100];
  448           int16_t csum;
  449           size_t datalen;
  450 
  451           if (iph->ip_p == IPPROTO_TCP)
  452             {
  453               struct tcphdr * tcph;
  454               uint32_t nullecho;
  455               size_t tcplen;
  456 
  457               tcph = (struct tcphdr *) (buf + iph->ip_hl*4);
  458 
  459               conn = find_connection (iph->ip_src, tcph->source,
  460                                       iph->ip_dst, tcph->dest, TCPCON);
  461 
  462               if (tcph->syn && !tcph->ack && !tcph->ack_seq && conn == NULL)
  463                 {
  464                   int connfd;
  465 
  466                   connfd = socks_connect ();
  467                   if (connfd == Econnrefused)
  468                     {
  469                       csum = ip_tcpudp_csum (&iph->ip_src, &iph->ip_dst);
  470 
  471                       tcplen = build_tcp (reply + 20, csum, ntohs (tcph->dest),
  472                           ntohs (tcph->source), 0, ntohl (tcph->seq) + 1, 0, 1,
  473                           0, 1, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
  474 
  475                       build_ip (reply, 20 + tcplen, 0, IP_DF, 64, IPPROTO_TCP,
  476                                 iph->ip_dst, iph->ip_src);
  477 
  478                       write (tunfd, reply, 20 + tcplen);
  479                     }
  480                   else if (connfd < 0)
  481                     {
  482                       uint8_t _type, _code;
  483                       size_t icmplen;
  484 
  485                       if (connfd == Ettlexpired)
  486                         _type = 11, _code = 0;
  487                       else if (connfd == Ehostunreach)
  488                         _type = 3, _code = 1;
  489                       else
  490                         _type = 3, _code = 0;
  491 
  492                       icmplen = build_icmp (reply + 20, _type, _code,
  493                                             (struct ip *) buf);
  494 
  495                       build_ip (reply, 20 + icmplen, 0, 0, 64, IPPROTO_ICMP,
  496                                 iph->ip_dst, iph->ip_src);
  497 
  498                       write (tunfd, reply, 20 + icmplen);
  499                     }
  500                   else
  501                     {
  502                       conn = malloc (sizeof (struct connection));
  503 
  504                       conn->local.sin_family = AF_INET;
  505                       conn->local.sin_addr = iph->ip_src;
  506                       conn->local.sin_port = tcph->source;
  507                       conn->remote.sin_family = AF_INET;
  508                       conn->remote.sin_addr = iph->ip_dst;
  509                       conn->remote.sin_port = tcph->dest;
  510 
  511                       conn->type = TCPCON;
  512                       conn->fd = connfd;
  513                       conn->status = 0;
  514 
  515                       conn->prev = NULL;
  516                       if (first_connection)
  517                         first_connection->prev = conn;
  518                       conn->next = first_connection;
  519                       first_connection = conn;
  520 
  521                       conn->buffer = NULL;
  522                       conn->buflen = 0;
  523 
  524                       parse_tcp_opts (buf + 40, (tcph->doff-5)*4, &conn->mss,
  525                           NULL, NULL, &conn->echo, &nullecho);
  526                       conn->seq = rand ();
  527                       conn->ack_seq = ntohl (tcph->seq) + 1;
  528                       conn->fin = 0;
  529 
  530                       conn->id = rand ();
  531 
  532                       memcpy (conn->orig, buf, 68);
  533 
  534                       data.ptr = (void *) conn;
  535                       poller_add (poller, connfd, POLLERIN, data);
  536                     }
  537                 }
  538               else if (conn != NULL && conn->status == 2)
  539                 {
  540                   if (tcph->rst)
  541                     goto connterm;
  542 
  543                   parse_tcp_opts (buf + 40, (tcph->doff-5)*4, NULL, NULL, NULL,
  544                       &conn->echo, &nullecho);
  545 
  546                   datalen = ntohs (iph->ip_len) - 20 - tcph->doff*4;
  547                   if (datalen > 0 && !(conn->fin & 1))
  548                     {
  549                       conn->buffer = realloc (conn->buffer,
  550                                               conn->buflen + datalen);
  551                       memcpy (conn->buffer + conn->buflen,
  552                               ((char *) tcph) + tcph->doff*4, datalen);
  553                       conn->buflen += datalen;
  554                       conn->ack_seq += datalen;
  555                     }
  556 
  557                   if (tcph->psh && !(conn->fin & 1))
  558                     {
  559                       if (write (conn->fd, conn->buffer, conn->buflen) < conn->buflen)
  560                         fprintf (stderr, "Could not write everything!\n");
  561 
  562                       free (conn->buffer);
  563                       conn->buffer = NULL;
  564                       conn->buflen = 0;
  565                     }
  566 
  567                   if (tcph->fin)
  568                     {
  569                       conn->fin |= 1;
  570                       if (conn->fin < 3)
  571                         shutdown (conn->fd, SHUT_WR);
  572                       conn->ack_seq ++;
  573                     }
  574 
  575                   if (tcph->ack && ((!tcph->fin && datalen > 0)
  576                       || (tcph->fin && conn->fin == 3)))
  577                     {
  578                       csum = ip_tcpudp_csum (&iph->ip_src, &iph->ip_dst);
  579 
  580                       tcplen = build_tcp (reply + 20, csum, ntohs (tcph->dest),
  581                           ntohs (tcph->source), conn->seq, conn->ack_seq, 0, 1,
  582                           0, 0, 0, 65535, 0, 0, 0, time (NULL), conn->echo,
  583                           NULL, 0);
  584 
  585                       build_ip (reply, 20 + tcplen, conn->id++, IP_DF, 64,
  586                           IPPROTO_TCP, iph->ip_dst, iph->ip_src);
  587 
  588                       write (tunfd, reply, 20 + tcplen);
  589                     }
  590 
  591                   if (conn->fin == 3)
  592                     {
  593 connterm:
  594                       close (conn->fd);
  595                       poller_remove (poller, conn->fd);
  596                       remove_connection (conn);
  597                     }
  598                 }
  599             }
  600           else if (iph->ip_p == IPPROTO_UDP)
  601             {
  602               struct udphdr * udph;
  603               size_t udplen;
  604 
  605               udph = (struct udphdr *) (buf + iph->ip_hl*4);
  606 
  607               conn = find_connection (iph->ip_src, udph->source,
  608                                       (struct in_addr) {INADDR_ANY}, 0,
  609                                       UDPCON);
  610 
  611               if (conn == NULL)
  612                 {
  613                   int connfd;
  614 
  615                   connfd = socks_connect ();
  616                   if (connfd < 0)
  617                     {
  618                       uint8_t _type, _code;
  619                       size_t icmplen;
  620 
  621                       if (connfd == Ettlexpired)
  622                         _type = 11, _code = 0;
  623                       else if (connfd == Econnrefused)
  624                         _type = 3, _code = 3;
  625                       else if (connfd == Ehostunreach)
  626                         _type = 3, _code = 1;
  627                       else
  628                         _type = 3, _code = 0;
  629 
  630                       icmplen = build_icmp (reply + 20, _type, _code,
  631                                             (struct ip *) buf);
  632 
  633                       build_ip (reply, 20 + icmplen, 0, 0, 64, IPPROTO_ICMP,
  634                                 iph->ip_dst, iph->ip_src);
  635 
  636                       write (tunfd, reply, 20 + icmplen);
  637                     }
  638                   else
  639                     {
  640                       conn = malloc (sizeof (struct connection));
  641 
  642                       conn->local.sin_family = AF_INET;
  643                       conn->local.sin_addr = iph->ip_src;
  644                       conn->local.sin_port = udph->source;
  645                       conn->remote.sin_family = AF_INET;
  646                       conn->remote.sin_addr.s_addr = INADDR_ANY;
  647                       conn->remote.sin_port = 0;
  648 
  649                       conn->type = UDPCON;
  650                       conn->fd = connfd;
  651                       conn->status = 0;
  652 
  653                       conn->prev = NULL;
  654                       if (first_connection)
  655                         first_connection->prev = conn;
  656                       conn->next = first_connection;
  657                       first_connection = conn;
  658 
  659                       datalen = ntohs (udph->len) - 8;
  660                       conn->buffer = malloc (datalen + 10);
  661                       conn->buflen = datalen + 10;
  662                       memcpy (conn->buffer + 10, buf + iph->ip_hl*4 + 8,
  663                               conn->buflen - 10);
  664 
  665                       conn->buffer[0] = 0;
  666                       conn->buffer[1] = 0;
  667                       conn->buffer[2] = 0;
  668                       conn->buffer[3] = 1;
  669                       memcpy (conn->buffer + 4, &iph->ip_dst, 4);
  670                       memcpy (conn->buffer + 8, &udph->dest, 2);
  671 
  672                       conn->id = rand ();
  673 
  674                       memcpy (conn->orig, buf, 68);
  675 
  676                       data.ptr = (void *) conn;
  677                       poller_add (poller, connfd, POLLERIN, data);
  678                     }
  679                 }
  680               else
  681                 {
  682                   datalen = ntohs (udph->len) - 8;
  683 
  684                   if (datalen)
  685                     {
  686                       conn->buffer = realloc (conn->buffer,
  687                                               conn->buflen + datalen);
  688                       memcpy (conn->buffer + conn->buflen, ((char *) udph) + 8,
  689                               datalen);
  690                       conn->buflen += datalen;
  691                     }
  692 
  693                   if (conn->status == 2 && conn->buffer != NULL
  694                       && conn->buflen > 0)
  695                     {
  696                       memcpy (conn->buffer + 4, &iph->ip_dst, 4);
  697                       memcpy (conn->buffer + 8, &udph->dest, 2);
  698 
  699                       if (write (conn->fd, conn->buffer, conn->buflen) < conn->buflen)
  700                         {
  701                           fprintf (stderr, "Could not write everything!\n");
  702                         }
  703 
  704                       conn->buffer = realloc (conn->buffer, 10);
  705                       conn->buflen = 10;
  706                     }
  707                 }
  708             }
  709         }
  710       else if (iph->ip_v == 6)
  711         {
  712           /* IPv6 zatial nepodporujeme */
  713           struct ip6_hdr * ip6h;
  714         }
  715     }
  716   else
  717     {
  718       struct connection * conn = (struct connection *) data.ptr;
  719       char buf[65536], reply[65536];
  720       size_t plen, icmplen;
  721       int16_t csum;
  722       ssize_t nr;
  723 
  724       if (conn->status < 2)
  725         {
  726           conn->status = socks_connect2 (conn);
  727           if (conn->status == Econnrefused && conn->type == TCPCON)
  728             {
  729               csum = ip_tcpudp_csum (&conn->local.sin_addr, &conn->remote.sin_addr);
  730 
  731               plen = build_tcp (reply + 20, csum, ntohs (conn->remote.sin_port),
  732                   ntohs (conn->local.sin_port), 0, conn->ack_seq, 0, 1,
  733                   0, 1, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
  734 
  735               build_ip (reply, 20 + plen, 0, IP_DF, 64, IPPROTO_TCP,
  736                         conn->remote.sin_addr, conn->local.sin_addr);
  737 
  738               write (tunfd, reply, 20 + plen);
  739             }
  740           else if (conn->status < 0)
  741             {
  742               uint8_t _type, _code;
  743               size_t icmplen;
  744 
  745               if (conn->status == Ettlexpired)
  746                 _type = 11, _code = 0;
  747               else if (conn->status == Econnrefused)
  748                 _type = 3, _code = 3;
  749               else if (conn->status == Ehostunreach)
  750                 _type = 3, _code = 1;
  751               else
  752                 _type = 3, _code = 0;
  753 
  754               icmplen = build_icmp (reply + 20, _type, _code,
  755                                     (struct ip *) conn->orig);
  756 
  757               build_ip (reply, 20 + icmplen, 0, 0, 64, IPPROTO_ICMP,
  758                         conn->remote.sin_addr, conn->local.sin_addr);
  759 
  760               write (tunfd, reply, 20 + icmplen);
  761             }
  762           else if (conn->status == 2 && conn->type == TCPCON)
  763             {
  764               csum = ip_tcpudp_csum (&conn->local.sin_addr,
  765                                      &conn->remote.sin_addr);
  766 
  767               plen = build_tcp (reply + 20, csum, ntohs (conn->remote.sin_port),
  768                   ntohs (conn->local.sin_port), conn->seq - 1, conn->ack_seq, 1,
  769                   1, 0, 0, 0, 65535, conn->mss, 0, 1, time (NULL), conn->echo,
  770                   NULL, 0);
  771 
  772               build_ip (reply, 20 + plen, 0, IP_DF, 64, IPPROTO_TCP,
  773                         conn->remote.sin_addr, conn->local.sin_addr);
  774 
  775               write (tunfd, reply, 20 + plen);
  776               return;
  777             }
  778           else if (conn->status == 2 && conn->type == UDPCON && conn->buflen)
  779             {
  780               if (write (conn->fd, conn->buffer, conn->buflen) < conn->buflen)
  781                 fprintf (stderr, "Could not write everything!\n");
  782 
  783               conn->buffer = realloc (conn->buffer, 10);
  784               conn->buflen = 10;
  785               return;
  786             }
  787           else
  788             return;
  789 
  790           poller_remove (poller, conn->fd);
  791           remove_connection (conn);
  792           return;
  793         }
  794 
  795       nr = read (conn->fd, buf, 65536);
  796       if (nr < 1)
  797         {
  798           close (conn->fd);
  799           poller_remove (poller, conn->fd);
  800 
  801           if (conn->type == UDPCON)
  802             {
  803               remove_connection (conn);
  804               return;
  805             }
  806 
  807           conn->fin |= 2;
  808 
  809           csum = ip_tcpudp_csum (&conn->local.sin_addr, &conn->remote.sin_addr);
  810 
  811           plen = build_tcp (reply + 20, csum, ntohs (conn->remote.sin_port),
  812               ntohs (conn->local.sin_port), conn->seq, conn->ack_seq,
  813               0, 1, 0, 0, 1, 65535, 0, 0, 0, time (NULL), conn->echo, NULL, 0);
  814 
  815           build_ip (reply, 20 + plen, conn->id++, IP_DF, 64, IPPROTO_TCP,
  816               conn->remote.sin_addr, conn->local.sin_addr);
  817 
  818           write (tunfd, reply, 20 + plen);
  819 
  820           conn->seq ++;
  821 
  822           if (conn->fin == 3)
  823             remove_connection (conn);
  824         }
  825       else if (conn->type == TCPCON || (conn->type == UDPCON && conn->buflen > 10
  826                && !memcmp (conn->buffer, (char[]) {0, 0, 0, 1}, 4)))
  827         {
  828           csum = ip_tcpudp_csum (&conn->local.sin_addr, &conn->remote.sin_addr);
  829 
  830           if (conn->type == TCPCON)
  831             plen = build_tcp (reply + 20, csum, ntohs (conn->remote.sin_port),
  832                 ntohs (conn->local.sin_port), conn->seq, conn->ack_seq,
  833                 0, 1, 1, 0, 0, 65535, 0, 0, 0, time (NULL), conn->echo, buf, nr);
  834           else
  835             plen = build_udp (reply + 20, csum, ntohs (*(uint16_t *) (conn->buffer + 8)),
  836                 ntohs (conn->local.sin_port), buf + 10, nr - 10);
  837 
  838           build_ip (reply, 20 + plen, conn->id++, IP_DF, 64,
  839               conn->type == TCPCON ? IPPROTO_TCP : IPPROTO_UDP,
  840               conn->type == TCPCON ? conn->remote.sin_addr
  841               : (*(struct in_addr *) (conn->buffer + 4)), conn->local.sin_addr);
  842 
  843           conn->seq += nr;
  844 
  845           write (tunfd, reply, 20 + plen);
  846         }
  847     }
  848 }
  849 
  850 int
  851 main (int argc, char ** argv)
  852 {
  853   char ifnam[IFNAMSIZ], * tmp;
  854   long int port;
  855   pollerdata_t data;
  856   struct connection * conn, * nextconn;
  857 
  858   srand (time (NULL) ^ getpid ());
  859 
  860   if (argc < 4)
  861     {
  862       fprintf (stderr, "usage: %s <tun_interface> <socks_server_ip> "
  863                        "<socks_server_port>\n\n", argv[0]);
  864       exit (EXIT_FAILURE);
  865     }
  866 
  867   socks_server.sin_family = AF_INET;
  868 
  869   if (!inet_pton (AF_INET, argv[2], &socks_server.sin_addr.s_addr))
  870     {
  871       fprintf (stderr, "Invalid SOCKS server IP address!\n\n");
  872       exit (EXIT_FAILURE);
  873     }
  874 
  875   port = strtol (argv[3], &tmp, 10);
  876   if (*tmp != '\0' || port < 1 || port > 65535)
  877     {
  878       fprintf (stderr, "Invalid SOCKS server port!\n\n");
  879       exit (EXIT_FAILURE);
  880     }
  881 
  882   socks_server.sin_port = htons (port);
  883 
  884   strcpy (ifnam, argv[1]);
  885   tunfd = tun_alloc (ifnam);
  886   if (tunfd < 0)
  887     {
  888       fprintf (stderr, "Cannot allocate tun interface %s!\n\n", ifnam);
  889       exit (EXIT_FAILURE);
  890     }
  891 
  892   poller = poller_create ();
  893   if (poller < 0)
  894     {
  895       fprintf (stderr, "Cannot create poller!\n\n");
  896       close (tunfd);
  897       exit (EXIT_FAILURE);
  898     }
  899 
  900   data.ptr = NULL;
  901   poller_add (poller, tunfd, POLLERIN, data);
  902 
  903   while (poller_poll (poller, -1, polled) > 0)
  904     ;
  905 
  906   for (conn = first_connection; conn != NULL; conn = nextconn)
  907     {
  908       nextconn = conn->next;
  909       poller_remove (poller, conn->fd);
  910       close (conn->fd);
  911       free (conn);
  912     }
  913 
  914   poller_destroy (poller);
  915   close (tunfd);
  916   exit (0);
  917 }
  918