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 "if_pppox.h" //Yau del 52#include <linux/if_pppox.h> 53 54#include <stdio.h> 55#include <stdlib.h> 56 57 58 59extern char** environ; 60 61char pppd_version[] = PPPD_VERSION; 62extern int new_style_driver; 63 64 65char *pptp_server = NULL; 66char *pptp_client = NULL; 67char *pptp_phone = NULL; 68int pptp_sock=-1; 69int pptp_timeout=100000; 70struct in_addr localbind = { INADDR_NONE }; 71 72static int callmgr_sock; 73static int pptp_fd; 74int call_ID; 75 76//static struct in_addr get_ip_address(char *name); 77static int open_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window); 78static void launch_callmgr(int call_is,struct in_addr inetaddr, char *phonenr,int window); 79static int get_call_id(int sock, pid_t gre, pid_t pppd, u_int16_t *peer_call_id); 80 81//static int pptp_devname_hook(char *cmd, char **argv, int doit); 82static option_t Options[] = 83{ 84 { "pptp_server", o_string, &pptp_server, 85 "PPTP Server" }, 86 { "pptp_client", o_string, &pptp_client, 87 "PPTP Client" }, 88 { "pptp_sock",o_int, &pptp_sock, 89 "PPTP socket" }, 90 { "pptp_phone", o_string, &pptp_phone, 91 "PPTP Phone number" }, 92 { NULL } 93}; 94 95static int pptp_connect(void); 96//static void pptp_send_config(int mtu,u_int32_t asyncmap,int pcomp,int accomp); 97//static void pptp_recv_config(int mru,u_int32_t asyncmap,int pcomp,int accomp); 98static void pptp_disconnect(void); 99 100struct channel pptp_channel = { 101 options: Options, 102 //process_extra_options: &PPPOEDeviceOptions, 103 check_options: NULL, 104 connect: &pptp_connect, 105 disconnect: &pptp_disconnect, 106 establish_ppp: &generic_establish_ppp, 107 disestablish_ppp: &generic_disestablish_ppp, 108 //send_config: &pptp_send_config, 109 //recv_config: &pptp_recv_config, 110 close: NULL, 111 cleanup: NULL 112}; 113 114static int pptp_start_server(void) 115{ 116 pptp_fd=pptp_sock; 117 sprintf(ppp_devnam,"pptp (%s)",pptp_client); 118 119 return pptp_fd; 120} 121static int pptp_start_client(void) 122{ 123 socklen_t len; 124 struct sockaddr_pppox src_addr,dst_addr; 125 struct hostent *hostinfo; 126 127 hostinfo=gethostbyname(pptp_server); 128 if (!hostinfo) 129 { 130 error("PPTP: Unknown host %s\n", pptp_server); 131 return -1; 132 } 133 dst_addr.sa_addr.pptp.sin_addr=*(struct in_addr*)hostinfo->h_addr; 134 { 135 int sock; 136 struct sockaddr_in addr; 137 len=sizeof(addr); 138 addr.sin_addr=dst_addr.sa_addr.pptp.sin_addr; 139 addr.sin_family=AF_INET; 140 addr.sin_port=htons(1700); 141 sock=socket(AF_INET,SOCK_DGRAM,0); 142 if (connect(sock,(struct sockaddr*)&addr,sizeof(addr))) 143 { 144 close(sock); 145 error("PPTP: connect failed (%s)\n",strerror(errno)); 146 return -1; 147 } 148 getsockname(sock,(struct sockaddr*)&addr,&len); 149 src_addr.sa_addr.pptp.sin_addr=addr.sin_addr; 150 close(sock); 151 } 152 //info("PPTP: connect server=%s\n",inet_ntoa(conn.sin_addr)); 153 //conn.loc_addr.s_addr=INADDR_NONE; 154 //conn.timeout=1; 155 //conn.window=pptp_window; 156 157 src_addr.sa_family=AF_PPPOX; 158 src_addr.sa_protocol=PX_PROTO_PPTP; 159 src_addr.sa_addr.pptp.call_id=0; 160 161 dst_addr.sa_family=AF_PPPOX; 162 dst_addr.sa_protocol=PX_PROTO_PPTP; 163 dst_addr.sa_addr.pptp.call_id=0; 164 165 pptp_fd=socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_PPTP); 166 if (pptp_fd<0) 167 { 168 error("PPTP: failed to create PPTP socket (%s)\n",strerror(errno)); 169 return -1; 170 } 171 if (bind(pptp_fd,(struct sockaddr*)&src_addr,sizeof(src_addr))) 172 { 173 close(pptp_fd); 174 error("PPTP: failed to bind PPTP socket (%s)\n",strerror(errno)); 175 return -1; 176 } 177 len=sizeof(src_addr); 178 getsockname(pptp_fd,(struct sockaddr*)&src_addr,&len); 179 call_ID=src_addr.sa_addr.pptp.call_id; 180 181 do { 182 /* 183 * Open connection to call manager (Launch call manager if necessary.) 184 */ 185 callmgr_sock = open_callmgr(src_addr.sa_addr.pptp.call_id,dst_addr.sa_addr.pptp.sin_addr, pptp_phone,50); 186 if (callmgr_sock<0) 187 { 188 close(pptp_fd); 189 return -1; 190 } 191 /* Exchange PIDs, get call ID */ 192 } while (get_call_id(callmgr_sock, getpid(), getpid(), &dst_addr.sa_addr.pptp.call_id) < 0); 193 194 if (connect(pptp_fd,(struct sockaddr*)&dst_addr,sizeof(dst_addr))) 195 { 196 close(callmgr_sock); 197 close(pptp_fd); 198 error("PPTP: failed to connect PPTP socket (%s)\n",strerror(errno)); 199 return -1; 200 } 201 202 sprintf(ppp_devnam,"pptp (%s)",pptp_server); 203 204 return pptp_fd; 205} 206static int pptp_connect(void) 207{ 208 if ((!pptp_server && !pptp_client) || (pptp_server && pptp_client)) 209 { 210 fatal("PPTP: unknown mode (you must specify pptp_server or pptp_client option)"); 211 return -1; 212 } 213 214 if (pptp_server) return pptp_start_client(); 215 return pptp_start_server(); 216} 217 218static void pptp_disconnect(void) 219{ 220 if (pptp_server) close(callmgr_sock); 221 close(pptp_fd); 222} 223 224static int open_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window) 225{ 226 /* Try to open unix domain socket to call manager. */ 227 struct sockaddr_un where; 228 const int NUM_TRIES = 3; 229 int i, fd; 230 pid_t pid; 231 int status; 232 /* Open socket */ 233 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 234 { 235 fatal("Could not create unix domain socket: %s", strerror(errno)); 236 } 237 /* Make address */ 238 callmgr_name_unixsock(&where, inetaddr, localbind); 239 for (i = 0; i < NUM_TRIES; i++) 240 { 241 if (connect(fd, (struct sockaddr *) &where, sizeof(where)) < 0) 242 { 243 /* couldn't connect. We'll have to launch this guy. */ 244 245 unlink (where.sun_path); 246 247 /* fork and launch call manager process */ 248 switch (pid = fork()) 249 { 250 case -1: /* failure */ 251 fatal("fork() to launch call manager failed."); 252 case 0: /* child */ 253 { 254 close (fd); 255 close(pptp_fd); 256 /* close the pty and gre in the call manager */ 257 // close(pty_fd); 258 //close(gre_fd); 259 launch_callmgr(call_id,inetaddr, phonenr,window); 260 } 261 default: /* parent */ 262 waitpid(pid, &status, 0); 263 if (status!= 0) 264 { 265 close(fd); 266 error("Call manager exited with error %d", status); 267 return -1; 268 } 269 break; 270 } 271 sleep(1); 272 } 273 else return fd; 274 } 275 close(fd); 276 error("Could not launch call manager after %d tries.", i); 277 return -1; /* make gcc happy */ 278} 279 280/*** call the call manager main ***********************************************/ 281static void launch_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window) 282{ 283 char win[10]; 284 char call[10]; 285 char *my_argv[9] = { "pptp", inet_ntoa(inetaddr), "--call_id",call,"--phone",phonenr,"--window",win,NULL }; 286 char buf[128]; 287 sprintf(win,"%u",window); 288 sprintf(call,"%u",call_id); 289 snprintf(buf, sizeof(buf), "pptp: call manager for %s", my_argv[1]); 290 //inststr(argc, argv, envp, buf); 291 exit(callmgr_main(8, my_argv, environ)); 292} 293 294/*** exchange data with the call manager *************************************/ 295/* XXX need better error checking XXX */ 296static int get_call_id(int sock, pid_t gre, pid_t pppd, 297 u_int16_t *peer_call_id) 298{ 299 u_int16_t m_call_id, m_peer_call_id; 300 /* write pid's to socket */ 301 /* don't bother with network byte order, because pid's are meaningless 302 * outside the local host. 303 */ 304 int rc; 305 rc = write(sock, &gre, sizeof(gre)); 306 if (rc != sizeof(gre)) 307 return -1; 308 rc = write(sock, &pppd, sizeof(pppd)); 309 if (rc != sizeof(pppd)) 310 return -1; 311 rc = read(sock, &m_call_id, sizeof(m_call_id)); 312 if (rc != sizeof(m_call_id)) 313 return -1; 314 rc = read(sock, &m_peer_call_id, sizeof(m_peer_call_id)); 315 if (rc != sizeof(m_peer_call_id)) 316 return -1; 317 /* 318 * XXX FIXME ... DO ERROR CHECKING & TIME-OUTS XXX 319 * (Rhialto: I am assuming for now that timeouts are not relevant 320 * here, because the read and write calls would return -1 (fail) when 321 * the peer goes away during the process. We know it is (or was) 322 * running because the connect() call succeeded.) 323 * (James: on the other hand, if the route to the peer goes away, we 324 * wouldn't get told by read() or write() for quite some time.) 325 */ 326 *peer_call_id = m_peer_call_id; 327 return 0; 328} 329 330void plugin_init(void) 331{ 332 /*if (!ppp_available() && !new_style_driver) 333 { 334 fatal("Linux kernel does not support PPP -- are you running 2.4.x?"); 335 }*/ 336 337 add_options(Options); 338 339 info("PPTP plugin version %s compiled for pppd-%s, linux-%s", 340 VERSION, PPPD_VERSION,KERNELVERSION); 341 342 the_channel = &pptp_channel; 343 modem = 0; 344} 345 346