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