1/*************************************************************************** 2 * Copyright (C) 2006 by Kozlov D. * 3 * xeb@mail.ru * 4 * * 5 * This program is free software; you can redistribute it and/or modify * 6 * it under the terms of the GNU General Public License as published by * 7 * the Free Software Foundation; either version 2 of the License, or * 8 * (at your option) any later version. * 9 * * 10 * This program is distributed in the hope that it will be useful, * 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 * GNU General Public License for more details. * 14 * * 15 * You should have received a copy of the GNU General Public License * 16 * along with this program; if not, write to the * 17 * Free Software Foundation, Inc., * 18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 19 ***************************************************************************/ 20 21 22#ifdef HAVE_CONFIG_H 23#include <config.h> 24#endif 25 26#include <netinet/in.h> 27#include <arpa/inet.h> 28#include <sys/un.h> 29#include <netdb.h> 30#include <stdio.h> 31#include <string.h> 32#include <stdlib.h> 33#include <syslog.h> 34#include <unistd.h> 35#include <signal.h> 36#include <errno.h> 37#include <fcntl.h> 38#include <sys/wait.h> 39#include <sys/ioctl.h> 40 41#include "pppd/pppd.h" 42#include "pppd/fsm.h" 43#include "pppd/lcp.h" 44#include "pppd/ipcp.h" 45#include "pppd/ccp.h" 46#include "pppd/pathnames.h" 47 48#include "pptp_callmgr.h" 49#include <net/if.h> 50#include <net/ethernet.h> 51#include <linux/if_pppox.h> 52 53#include <stdio.h> 54#include <stdlib.h> 55 56#include <net/route.h> 57#include <features.h> 58#include <resolv.h> 59#define sin_addr(s) (((struct sockaddr_in *)(s))->sin_addr) 60 61extern char** environ; 62 63char pppd_version[] = VERSION; 64extern int new_style_driver; 65 66 67char *pptp_server = NULL; 68char *pptp_client = NULL; 69char *pptp_phone = NULL; 70int pptp_sock=-1; 71int pptp_timeout=100000; 72int log_level = 0; 73struct in_addr localbind = { INADDR_NONE }; 74struct rtentry rt; 75 76static int callmgr_sock; 77static int pptp_fd; 78int call_ID; 79 80//static struct in_addr get_ip_address(char *name); 81static int open_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window); 82static void launch_callmgr(int call_is,struct in_addr inetaddr, char *phonenr,int window); 83static int get_call_id(int sock, pid_t gre, pid_t pppd, u_int16_t *peer_call_id); 84 85static int route_add(const struct in_addr inetaddr, struct rtentry *rt); 86static int route_del(struct rtentry *rt); 87 88//static int pptp_devname_hook(char *cmd, char **argv, int doit); 89static option_t Options[] = 90{ 91 { "pptp_server", o_string, &pptp_server, 92 "PPTP Server" }, 93 { "pptp_client", o_string, &pptp_client, 94 "PPTP Client" }, 95 { "pptp_sock",o_int, &pptp_sock, 96 "PPTP socket" }, 97 { "pptp_phone", o_string, &pptp_phone, 98 "PPTP Phone number" }, 99 { "loglevel", o_int, &log_level, 100 "debugging level (0=low, 1=default, 2=high)"}, 101 { NULL } 102}; 103 104static int pptp_connect(void); 105//static void pptp_send_config(int mtu,u_int32_t asyncmap,int pcomp,int accomp); 106//static void pptp_recv_config(int mru,u_int32_t asyncmap,int pcomp,int accomp); 107static void pptp_disconnect(void); 108 109struct channel pptp_channel = { 110 options: Options, 111 //process_extra_options: &PPPOEDeviceOptions, 112 check_options: NULL, 113 connect: &pptp_connect, 114 disconnect: &pptp_disconnect, 115 establish_ppp: &generic_establish_ppp, 116 disestablish_ppp: &generic_disestablish_ppp, 117 //send_config: &pptp_send_config, 118 //recv_config: &pptp_recv_config, 119 close: NULL, 120 cleanup: NULL 121}; 122 123static int pptp_start_server(void) 124{ 125 pptp_fd=pptp_sock; 126 sprintf(ppp_devnam,"pptp (%s)",pptp_client); 127 128 return pptp_fd; 129} 130static int pptp_start_client(void) 131{ 132 socklen_t len; 133 struct sockaddr_pppox src_addr,dst_addr; 134 struct hostent *hostinfo; 135 136#if !defined(__UCLIBC__) \ 137 || (__UCLIBC_MAJOR__ == 0 \ 138 && (__UCLIBC_MINOR__ < 9 || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 31))) 139 /* force ns refresh from resolv.conf with uClibc pre-0.9.31 */ 140 res_init(); 141#endif 142 hostinfo=gethostbyname(pptp_server); 143 if (!hostinfo) 144 { 145 error("PPTP: Unknown host %s\n", pptp_server); 146 return -1; 147 } 148 dst_addr.sa_addr.pptp.sin_addr=*(struct in_addr*)hostinfo->h_addr; 149 150 memset(&rt, 0, sizeof(rt)); 151 route_add(dst_addr.sa_addr.pptp.sin_addr, &rt); 152 153 { 154 int sock; 155 struct sockaddr_in addr; 156 len=sizeof(addr); 157 addr.sin_addr=dst_addr.sa_addr.pptp.sin_addr; 158 addr.sin_family=AF_INET; 159 addr.sin_port=htons(1700); 160 sock=socket(AF_INET,SOCK_DGRAM,0); 161 if (connect(sock,(struct sockaddr*)&addr,sizeof(addr))) 162 { 163 close(sock); 164 error("PPTP: connect failed (%s)\n",strerror(errno)); 165 return -1; 166 } 167 getsockname(sock,(struct sockaddr*)&addr,&len); 168 src_addr.sa_addr.pptp.sin_addr=addr.sin_addr; 169 close(sock); 170 } 171 //info("PPTP: connect server=%s\n",inet_ntoa(conn.sin_addr)); 172 //conn.loc_addr.s_addr=INADDR_NONE; 173 //conn.timeout=1; 174 //conn.window=pptp_window; 175 176 src_addr.sa_family=AF_PPPOX; 177 src_addr.sa_protocol=PX_PROTO_PPTP; 178 src_addr.sa_addr.pptp.call_id=0; 179 180 dst_addr.sa_family=AF_PPPOX; 181 dst_addr.sa_protocol=PX_PROTO_PPTP; 182 dst_addr.sa_addr.pptp.call_id=0; 183 184 pptp_fd=socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_PPTP); 185 if (pptp_fd<0) 186 { 187 error("PPTP: failed to create PPTP socket (%s)\n",strerror(errno)); 188 return -1; 189 } 190 if (bind(pptp_fd,(struct sockaddr*)&src_addr,sizeof(src_addr))) 191 { 192 close(pptp_fd); 193 error("PPTP: failed to bind PPTP socket (%s)\n",strerror(errno)); 194 return -1; 195 } 196 len=sizeof(src_addr); 197 getsockname(pptp_fd,(struct sockaddr*)&src_addr,&len); 198 call_ID=src_addr.sa_addr.pptp.call_id; 199 200 do { 201 /* 202 * Open connection to call manager (Launch call manager if necessary.) 203 */ 204 callmgr_sock = open_callmgr(src_addr.sa_addr.pptp.call_id,dst_addr.sa_addr.pptp.sin_addr, pptp_phone,50); 205 if (callmgr_sock<0) 206 { 207 close(pptp_fd); 208 return -1; 209 } 210 /* Exchange PIDs, get call ID */ 211 } while (get_call_id(callmgr_sock, getpid(), getpid(), &dst_addr.sa_addr.pptp.call_id) < 0); 212 213 if (connect(pptp_fd,(struct sockaddr*)&dst_addr,sizeof(dst_addr))) 214 { 215 close(callmgr_sock); 216 close(pptp_fd); 217 error("PPTP: failed to connect PPTP socket (%s)\n",strerror(errno)); 218 return -1; 219 } 220 221 sprintf(ppp_devnam,"pptp (%s)", inet_ntoa(dst_addr.sa_addr.pptp.sin_addr)); 222 223 return pptp_fd; 224} 225static int pptp_connect(void) 226{ 227 if ((!pptp_server && !pptp_client) || (pptp_server && pptp_client)) 228 { 229 fatal("PPTP: unknown mode (you must specify pptp_server or pptp_client option)"); 230 return -1; 231 } 232 233 if (pptp_server) return pptp_start_client(); 234 return pptp_start_server(); 235} 236 237static void pptp_disconnect(void) 238{ 239 if (pptp_server) close(callmgr_sock); 240 close(pptp_fd); 241 //route_del(&rt); // don't delete, as otherwise it would try to use pppX in demand mode 242} 243 244static int open_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window) 245{ 246 /* Try to open unix domain socket to call manager. */ 247 struct sockaddr_un where; 248 const int NUM_TRIES = 3; 249 int i, fd; 250 pid_t pid; 251 int status; 252 /* Open socket */ 253 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 254 { 255 fatal("Could not create unix domain socket: %s", strerror(errno)); 256 } 257 /* Make address */ 258 callmgr_name_unixsock(&where, inetaddr, localbind); 259 for (i = 0; i < NUM_TRIES; i++) 260 { 261 if (connect(fd, (struct sockaddr *) &where, sizeof(where)) < 0) 262 { 263 /* couldn't connect. We'll have to launch this guy. */ 264 265 unlink (where.sun_path); 266 267 /* fork and launch call manager process */ 268 switch (pid = fork()) 269 { 270 case -1: /* failure */ 271 fatal("fork() to launch call manager failed."); 272 case 0: /* child */ 273 { 274 close (fd); 275 close(pptp_fd); 276 /* close the pty and gre in the call manager */ 277 //close(pty_fd); 278 //close(gre_fd); 279 launch_callmgr(call_id,inetaddr, phonenr,window); 280 } 281 default: /* parent */ 282 waitpid(pid, &status, 0); 283 if (status!= 0) 284 { 285 close(fd); 286 error("Call manager exited with error %d", status); 287 return -1; 288 } 289 break; 290 } 291 sleep(1); 292 } 293 else return fd; 294 } 295 close(fd); 296 error("Could not launch call manager after %d tries.", i); 297 return -1; /* make gcc happy */ 298} 299 300/*** call the call manager main ***********************************************/ 301static void launch_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window) 302{ 303 char win[10]; 304 char call[10]; 305 char *my_argv[9] = { "pptp", inet_ntoa(inetaddr), "--call_id",call,"--phone",phonenr,"--window",win,NULL }; 306 char buf[128]; 307 sprintf(win,"%u",window); 308 sprintf(call,"%u",call_id); 309 snprintf(buf, sizeof(buf), "pptp: call manager for %s", my_argv[1]); 310 //inststr(argc, argv, envp, buf); 311 exit(callmgr_main(8, my_argv, environ)); 312} 313 314/*** exchange data with the call manager *************************************/ 315/* XXX need better error checking XXX */ 316static int get_call_id(int sock, pid_t gre, pid_t pppd, 317 u_int16_t *peer_call_id) 318{ 319 u_int16_t m_call_id, m_peer_call_id; 320 /* write pid's to socket */ 321 /* don't bother with network byte order, because pid's are meaningless 322 * outside the local host. 323 */ 324 int rc; 325 rc = write(sock, &gre, sizeof(gre)); 326 if (rc != sizeof(gre)) 327 return -1; 328 rc = write(sock, &pppd, sizeof(pppd)); 329 if (rc != sizeof(pppd)) 330 return -1; 331 rc = read(sock, &m_call_id, sizeof(m_call_id)); 332 if (rc != sizeof(m_call_id)) 333 return -1; 334 rc = read(sock, &m_peer_call_id, sizeof(m_peer_call_id)); 335 if (rc != sizeof(m_peer_call_id)) 336 return -1; 337 /* 338 * XXX FIXME ... DO ERROR CHECKING & TIME-OUTS XXX 339 * (Rhialto: I am assuming for now that timeouts are not relevant 340 * here, because the read and write calls would return -1 (fail) when 341 * the peer goes away during the process. We know it is (or was) 342 * running because the connect() call succeeded.) 343 * (James: on the other hand, if the route to the peer goes away, we 344 * wouldn't get told by read() or write() for quite some time.) 345 */ 346 *peer_call_id = m_peer_call_id; 347 return 0; 348} 349 350void plugin_init(void) 351{ 352 if (!ppp_available() && !new_style_driver) 353 fatal("Kernel doesn't support ppp_generic - needed for PPTP"); 354 355 add_options(Options); 356 357 info("PPTP plugin version %s compiled for pppd-%s", 358 PLUGINVERSION, VERSION); 359 360 the_channel = &pptp_channel; 361 modem = 0; 362} 363 364static int 365route_ctrl(int ctrl, struct rtentry *rt) 366{ 367 int s; 368 369 /* Open a raw socket to the kernel */ 370 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || ioctl(s, ctrl, rt) < 0) 371 warn("route_ctrl: %s", strerror(errno)); 372 else errno = 0; 373 374 close(s); 375 return errno; 376} 377 378static int 379route_del(struct rtentry *rt) 380{ 381 if (rt->rt_dev) { 382 route_ctrl(SIOCDELRT, rt); 383 free(rt->rt_dev), rt->rt_dev = NULL; 384 } 385 386 return 0; 387} 388 389static int 390route_add(const struct in_addr inetaddr, struct rtentry *rt) 391{ 392 char buf[256], dev[64]; 393 int metric, flags; 394 u_int32_t dest, mask; 395 396 FILE *f = fopen("/proc/net/route", "r"); 397 if (f == NULL) { 398 warn("/proc/net/route: %s", strerror(errno)); 399 return -1; 400 } 401 402 while (fgets(buf, sizeof(buf), f)) 403 { 404 if (sscanf(buf, "%63s %x %x %X %*s %*s %d %x", dev, &dest, 405 &sin_addr(&rt->rt_gateway).s_addr, &flags, &metric, &mask) != 6) 406 continue; 407 if ((flags & RTF_UP) == RTF_UP && (inetaddr.s_addr & mask) == dest && 408 (dest || strncmp(dev, "ppp", 3)) /* avoid default via pppX to avoid on-demand loops*/) 409 { 410 rt->rt_metric = metric + 1; 411 rt->rt_gateway.sa_family = AF_INET; 412 break; 413 } 414 } 415 416 fclose(f); 417 418 /* check for no route */ 419 if (rt->rt_gateway.sa_family != AF_INET) 420 { 421 /* warn("route_add: no route to host"); */ 422 return -1; 423 } 424 425 /* check for existing route to this host, 426 add if missing based on the existing routes */ 427 if (flags & RTF_HOST) { 428 /* warn("route_add: not adding existing route"); */ 429 return -1; 430 } 431 432 sin_addr(&rt->rt_dst) = inetaddr; 433 rt->rt_dst.sa_family = AF_INET; 434 435 sin_addr(&rt->rt_genmask).s_addr = INADDR_BROADCAST; 436 rt->rt_genmask.sa_family = AF_INET; 437 438 rt->rt_flags = RTF_UP | RTF_HOST; 439 if (flags & RTF_GATEWAY) 440 rt->rt_flags |= RTF_GATEWAY; 441 442 rt->rt_metric++; 443 rt->rt_dev = strdup(dev); 444 445 if (!rt->rt_dev) 446 { 447 warn("route_add: no memory"); 448 return -1; 449 } 450 451 if (!route_ctrl(SIOCADDRT, rt)) 452 return 0; 453 454 free(rt->rt_dev), rt->rt_dev = NULL; 455 456 return -1; 457} 458