1 /*
2     VTun - Virtual Tunnel over TCP/IP network.
3 
4     Copyright (C) 1998-2016  Maxim Krasnyansky <max_mk@yahoo.com>
5 
6     VTun has been derived from VPPP package by Maxim Krasnyansky.
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17  */
18 
19 /*
20  * $Id: udp_proto.c,v 1.10.2.4 2016/10/01 21:37:39 mtbishop Exp $
21  */
22 
23 #include "config.h"
24 
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <stdarg.h>
32 #include <sys/time.h>
33 #include <sys/wait.h>
34 #include <syslog.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/uio.h>
38 #include <errno.h>
39 
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
42 #endif
43 
44 #ifdef HAVE_NETINET_IN_SYSTM_H
45 #include <netinet/in_systm.h>
46 #endif
47 
48 #ifdef HAVE_NETINET_IP_H
49 #include <netinet/ip.h>
50 #endif
51 
52 #ifdef HAVE_NETINET_TCP_H
53 #include <netinet/udp.h>
54 #endif
55 
56 #include "vtun.h"
57 #include "lib.h"
58 
59 extern int is_rmt_fd_connected;
60 
61 /* Functions to read/write UDP frames. */
udp_write(int fd,char * buf,int len)62 int udp_write(int fd, char *buf, int len)
63 {
64      register char *ptr;
65      register int wlen;
66 
67      if (!is_rmt_fd_connected) return 0;
68 
69      ptr = buf - sizeof(short);
70 
71      *((unsigned short *)ptr) = htons(len);
72      len  = (len & VTUN_FSIZE_MASK) + sizeof(short);
73 
74      while( 1 ){
75 	if( (wlen = write(fd, ptr, len)) < 0 ){
76 	   if( errno == EAGAIN || errno == EINTR )
77 	      continue;
78 	   if( errno == ENOBUFS )
79 	      return 0;
80 	}
81 	/* Even if we wrote only part of the frame
82          * we can't use second write since it will produce
83          * another UDP frame */
84         return wlen;
85      }
86 }
87 
udp_read(int fd,char * buf)88 int udp_read(int fd, char *buf)
89 {
90      unsigned short hdr, flen;
91      struct iovec iv[2];
92      register int rlen;
93      struct sockaddr_in from;
94      socklen_t fromlen = sizeof(struct sockaddr);
95 
96      /* Late connect (NAT hack enabled) */
97      if (!is_rmt_fd_connected) {
98           while( 1 ){
99                if( (rlen = recvfrom(fd,buf,2,MSG_PEEK,(struct sockaddr *)&from,&fromlen)) < 0 ){
100                     if( errno == EAGAIN || errno == EINTR ) continue;
101                     else return rlen;
102                }
103                else break;
104           }
105           if( connect(fd,(struct sockaddr *)&from,fromlen) ){
106                vtun_syslog(LOG_ERR,"Can't connect socket");
107                return -1;
108           }
109           is_rmt_fd_connected = 1;
110      }
111 
112      /* Read frame */
113      iv[0].iov_len  = sizeof(short);
114      iv[0].iov_base = (char *) &hdr;
115      iv[1].iov_len  = VTUN_FRAME_SIZE + VTUN_FRAME_OVERHEAD;
116      iv[1].iov_base = buf;
117 
118      while( 1 ){
119         if( (rlen = readv(fd, iv, 2)) < 0 ){
120 	   if( errno == EAGAIN || errno == EINTR )
121 	      continue;
122 	   else
123      	      return rlen;
124 	}
125         hdr = ntohs(hdr);
126         flen = hdr & VTUN_FSIZE_MASK;
127 
128         if( rlen < 2 || (rlen-2) != flen )
129 	   return VTUN_BAD_FRAME;
130 
131 	return hdr;
132      }
133 }
134