1 /* 2 * Copyright (c) 1996, Nickolay Dudorov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 /* 30 * 'nos_tun' program configure tunN interface as a point-to-point 31 * connection with two "pseudo"-addresses between this host and 32 * 'target'. 33 * 34 * It uses Ip-over-Ip incapsulation ( protocol number 94 - IPIP) 35 * (known as NOS-incapsulation in CISCO-routers' terminology). 36 * 37 * 'nos_tun' can works with itself and CISCO-routers. 38 * (It may also work with Linux 'nos_tun's, but 39 * I have no Linux system here to test with). 40 * 41 * BUGS (or features ?): 42 * - you must specify ONE of the target host's addresses 43 * ( nos_tun sends and accepts packets only to/from this 44 * address ) 45 * - there can be only ONE tunnel between two hosts, 46 * more precisely - between given host and (one of) 47 * target hosts' address(es) 48 * (and why do you want more ?) 49 */ 50 51 #ifndef lint 52 static const char rcsid[] = 53 "$Id: nos-tun.c,v 1.3 1998/07/15 06:38:53 charnier Exp $"; 54 #endif /* not lint */ 55 56 #include <fcntl.h> 57 #include <netdb.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <syslog.h> 62 #include <sys/signal.h> 63 #include <sys/socket.h> 64 #include <sys/ioctl.h> 65 #include <netinet/in.h> 66 #include <netinet/in_systm.h> 67 #include <netinet/ip.h> 68 #include <net/if.h> 69 #include <arpa/inet.h> 70 #include <unistd.h> 71 72 /* Tunnel interface configuration stuff */ 73 static struct ifaliasreq ifra; 74 static struct ifreq ifrq; 75 76 /* Global descriptors */ 77 int net; /* socket descriptor */ 78 int tun; /* tunnel descriptor */ 79 80 static void usage __P((void)); 81 82 int Set_address(char *addr, struct sockaddr_in *sin) 83 { 84 struct hostent *hp; 85 86 bzero((char *)sin, sizeof(struct sockaddr)); 87 sin->sin_family = AF_INET; 88 if((sin->sin_addr.s_addr = inet_addr(addr)) == (u_long)-1) { 89 hp = gethostbyname(addr); 90 if (!hp) { 91 syslog(LOG_ERR,"unknown host %s", addr); 92 return 1; 93 } 94 sin->sin_family = hp->h_addrtype; 95 bcopy(hp->h_addr, (caddr_t)&sin->sin_addr, hp->h_length); 96 } 97 return 0; 98 } 99 100 int tun_open(char *devname, struct sockaddr *ouraddr, char *theiraddr) 101 { 102 int s; 103 struct sockaddr_in *sin; 104 105 /* Open tun device */ 106 tun = open (devname, O_RDWR); 107 if (tun < 0) { 108 syslog(LOG_ERR,"can't open %s - %m",devname); 109 return(1); 110 } 111 112 /* 113 * At first, name the interface. 114 */ 115 bzero((char *)&ifra, sizeof(ifra)); 116 bzero((char *)&ifrq, sizeof(ifrq)); 117 118 strncpy(ifrq.ifr_name, devname+5, IFNAMSIZ); 119 strncpy(ifra.ifra_name, devname+5, IFNAMSIZ); 120 121 s = socket(AF_INET, SOCK_DGRAM, 0); 122 if (s < 0) { 123 syslog(LOG_ERR,"can't open socket - %m"); 124 goto tunc_return; 125 } 126 127 /* 128 * Delete (previous) adresses for interface 129 * 130 * !!!! 131 * On FreeBSD this ioctl returns error 132 * when tunN have no addresses, so - log and ignore it. 133 * 134 */ 135 if (ioctl(s, SIOCDIFADDR, &ifra) < 0) { 136 syslog(LOG_ERR,"SIOCDIFADDR - %m"); 137 } 138 139 /* 140 * Set interface address 141 */ 142 sin = (struct sockaddr_in *)&(ifra.ifra_addr); 143 bcopy(ouraddr, sin, sizeof(struct sockaddr_in)); 144 sin->sin_len = sizeof(*sin); 145 146 /* 147 * Set destination address 148 */ 149 sin = (struct sockaddr_in *)&(ifra.ifra_broadaddr); 150 if(Set_address(theiraddr,sin)) { 151 syslog(LOG_ERR,"bad destination address: %s",theiraddr); 152 goto stunc_return; 153 } 154 sin->sin_len = sizeof(*sin); 155 156 if (ioctl(s, SIOCAIFADDR, &ifra) < 0) { 157 syslog(LOG_ERR,"can't set interface address - %m"); 158 goto stunc_return; 159 } 160 161 /* 162 * Now, bring up the interface. 163 */ 164 if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 165 syslog(LOG_ERR,"can't get interface flags - %m"); 166 goto stunc_return; 167 } 168 169 ifrq.ifr_flags |= IFF_UP; 170 if (!(ioctl(s, SIOCSIFFLAGS, &ifrq) < 0)) { 171 close(s); 172 return(0); 173 } 174 syslog(LOG_ERR,"can't set interface UP - %m"); 175 stunc_return: 176 close(s); 177 tunc_return: 178 close(tun); 179 return(1); 180 } 181 182 void Finish(int signum) 183 { 184 int s; 185 186 syslog(LOG_INFO,"exiting"); 187 188 close(net); 189 190 s = socket(AF_INET, SOCK_DGRAM, 0); 191 if (s < 0) { 192 syslog(LOG_ERR,"can't open socket - %m"); 193 goto closing_tun; 194 } 195 196 /* 197 * Shut down interface. 198 */ 199 if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 200 syslog(LOG_ERR,"can't get interface flags - %m"); 201 goto closing_fds; 202 } 203 204 ifrq.ifr_flags &= ~(IFF_UP|IFF_RUNNING); 205 if (ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 206 syslog(LOG_ERR,"can't set interface DOWN - %m"); 207 goto closing_fds; 208 } 209 210 /* 211 * Delete adresses for interface 212 */ 213 bzero(&ifra.ifra_addr, sizeof(ifra.ifra_addr)); 214 bzero(&ifra.ifra_broadaddr, sizeof(ifra.ifra_addr)); 215 bzero(&ifra.ifra_mask, sizeof(ifra.ifra_addr)); 216 if (ioctl(s, SIOCDIFADDR, &ifra) < 0) { 217 syslog(LOG_ERR,"can't delete interface's addresses - %m"); 218 } 219 closing_fds: 220 close(s); 221 closing_tun: 222 close(tun); 223 closelog(); 224 exit(signum); 225 } 226 227 int main (int argc, char **argv) 228 { 229 int c, len, ipoff; 230 231 char *devname = NULL; 232 char *point_to = NULL; 233 char *to_point = NULL; 234 char *target; 235 236 struct sockaddr t_laddr; /* Source address of tunnel */ 237 struct sockaddr whereto; /* Destination of tunnel */ 238 struct sockaddr_in *to; 239 240 char buf[0x2000]; /* Packets buffer */ 241 struct ip *ip = (struct ip *)buf; 242 243 fd_set rfds, wfds, efds; /* File descriptors for select() */ 244 int nfds; /* Return from select() */ 245 246 247 while ((c = getopt(argc, argv, "d:s:t:")) != -1) { 248 switch (c) { 249 case 'd': 250 to_point = optarg; 251 break; 252 case 's': 253 point_to = optarg; 254 break; 255 case 't': 256 devname = optarg; 257 break; 258 } 259 } 260 argc -= optind; 261 argv += optind; 262 263 if (argc != 1 || (devname == NULL) || 264 (point_to == NULL) || (to_point == NULL)) { 265 usage(); 266 } 267 268 target = *argv; 269 270 /* Establish logging through 'syslog' */ 271 openlog("nos_tun", LOG_PID, LOG_DAEMON); 272 273 if(Set_address(point_to, (struct sockaddr_in *)&t_laddr)) { 274 closelog(); 275 exit(2); 276 } 277 278 if(tun_open(devname, &t_laddr, to_point)) { 279 closelog(); 280 exit(3); 281 } 282 283 to = (struct sockaddr_in *)&whereto; 284 if(Set_address(target, to)) 285 Finish(4); 286 287 if ((net = socket(AF_INET, SOCK_RAW, 94)) < 0) { 288 syslog(LOG_ERR,"can't open socket - %m"); 289 Finish(5); 290 } 291 292 if (connect(net,&whereto,sizeof(struct sockaddr_in)) < 0 ) { 293 syslog(LOG_ERR,"can't connect to target - %m"); 294 close(net); 295 Finish(6); 296 } 297 298 /* Demonize it */ 299 daemon(0,0); 300 301 /* Install signal handlers */ 302 (void)signal(SIGHUP,Finish); 303 (void)signal(SIGINT,Finish); 304 (void)signal(SIGTERM,Finish); 305 306 for (;;) { 307 /* Set file descriptors for select() */ 308 FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 309 FD_SET(tun,&rfds); FD_SET(net,&rfds); 310 311 nfds = select(net+10,&rfds,&wfds,&efds,NULL); 312 if(nfds < 0) { 313 syslog(LOG_ERR,"interrupted select"); 314 close(net); 315 Finish(7); 316 } 317 if(nfds == 0) { /* Impossible ? */ 318 syslog(LOG_ERR,"timeout in select"); 319 close(net); 320 Finish(8); 321 } 322 323 324 if(FD_ISSET(net,&rfds)) { 325 /* Read from socket ... */ 326 len = read(net, buf, sizeof(buf)); 327 /* Check if this is "our" packet */ 328 if((ip->ip_src).s_addr == (to->sin_addr).s_addr) { 329 /* ... skip encapsulation headers ... */ 330 ipoff = (ip->ip_hl << 2); 331 /* ... and write to tun-device */ 332 write(tun,buf+ipoff,len-ipoff); 333 } 334 } 335 336 if(FD_ISSET(tun,&rfds)) { 337 /* Read from tun ... */ 338 len = read(tun, buf, sizeof(buf)); 339 /* ... and send to network */ 340 if(send(net, buf, len,0) <= 0) { 341 syslog(LOG_ERR,"can't send - %m"); 342 } 343 } 344 } 345 } 346 347 static void 348 usage() 349 { 350 fprintf(stderr, 351 "usage: nos_tun -t <tun_name> -s <source_addr> -d <dest_addr> <target_addr>\n"); 352 exit(1); 353 } 354 355