📄 pptp.c
字号:
/* at least one argument is required */ if (argc <= optind) usage(argv[0]); /* Get IP address for the hostname in argv[1] */ inetaddr = get_ip_address(argv[optind]); optind++; /* Find the ppp options, extract phone number */ pppdargc = argc - optind; pppdargv = argv + optind; log("The synchronous pptp option is %sactivated\n", syncppp ? "" : "NOT "); /* Now we have the peer address, bind the GRE socket early, before starting pppd. This prevents the ICMP Unreachable bug documented in <1026868263.2855.67.camel@jander> */ gre_fd = pptp_gre_bind(inetaddr); if (gre_fd < 0) { close(callmgr_sock); fatal("Cannot bind GRE socket, aborting."); } /* Find an open pty/tty pair. */ if(launchpppd){ rc = openpty (&pty_fd, &tty_fd, ttydev, NULL, NULL); if (rc < 0) { close(callmgr_sock); fatal("Could not find free pty."); } /* fork and wait. */ signal(SIGUSR1, do_nothing); /* don't die */ signal(SIGCHLD, do_nothing); /* don't ignore SIGCHLD */ parent_pid = getpid(); switch (child_pid = fork()) { case -1: fatal("Could not fork pppd process"); case 0: /* I'm the child! */ close (tty_fd); signal(SIGUSR1, SIG_DFL); child_pid = getpid(); break; default: /* parent */ close (pty_fd); /* * There is still a very small race condition here. If a signal * occurs after signaled is checked but before pause is called, * things will hang. */ if (!signaled) { pause(); /* wait for the signal */ } if (signaled == SIGCHLD) fatal("Child process died"); launch_pppd(ttydev, pppdargc, pppdargv); /* launch pppd */ perror("Error"); fatal("Could not launch pppd"); } } else { /* ! launchpppd */ pty_fd = tty_fd = STDIN_FILENO; /* close unused file descriptor, that is redirected to the pty */ close(STDOUT_FILENO); child_pid = getpid(); parent_pid = 0; /* don't kill pppd */ } do { /* * Open connection to call manager (Launch call manager if necessary.) */ callmgr_sock = open_callmgr(inetaddr, phonenr, argc, argv, envp, pty_fd, gre_fd); /* Exchange PIDs, get call ID */ } while (get_call_id(callmgr_sock, parent_pid, child_pid, &call_id, &peer_call_id) < 0); /* Send signal to wake up pppd task */ if (launchpppd) { kill(parent_pid, SIGUSR1); sleep(2); /* become a daemon */ if (!debug && daemon(0, 0) != 0) { perror("daemon"); } } else { /* re-open stderr as /dev/null to release it */ file2fd("/dev/null", "wb", STDERR_FILENO); } snprintf(buf, sizeof(buf), "pptp: GRE-to-PPP gateway on %s", ttyname(tty_fd)); inststr(argc, argv, envp, buf); if (sigsetjmp(env, 1)!= 0) goto shutdown; signal(SIGINT, sighandler); signal(SIGTERM, sighandler); signal(SIGKILL, sighandler); signal(SIGCHLD, sighandler); signal(SIGUSR1, sigstats); /* Do GRE copy until close. */ pptp_gre_copy(call_id, peer_call_id, pty_fd, gre_fd);shutdown: /* on close, kill all. */ if(launchpppd) kill(parent_pid, SIGTERM); close(pty_fd); close(callmgr_sock); exit(0);}/*** get the ipaddress coming from the command line ***************************/struct in_addr get_ip_address(char *name){ struct in_addr retval; struct hostent *host = gethostbyname(name); if (host == NULL) { if (h_errno == HOST_NOT_FOUND) fatal("gethostbyname '%s': HOST NOT FOUND", name); else if (h_errno == NO_ADDRESS) fatal("gethostbyname '%s': NO IP ADDRESS", name); else fatal("gethostbyname '%s': name server error", name); } if (host->h_addrtype != AF_INET) fatal("Host '%s' has non-internet address", name); memcpy(&retval.s_addr, host->h_addr, sizeof(retval.s_addr)); return retval;}/*** start the call manager ***************************************************/int open_callmgr(struct in_addr inetaddr, char *phonenr, int argc, char **argv, char **envp, int pty_fd, int gre_fd){ /* Try to open unix domain socket to call manager. */ struct sockaddr_un where; const int NUM_TRIES = 3; int i, fd; pid_t pid; int status; /* Open socket */ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { fatal("Could not create unix domain socket: %s", strerror(errno)); } /* Make address */ callmgr_name_unixsock(&where, inetaddr, localbind); for (i = 0; i < NUM_TRIES; i++) { if (connect(fd, (struct sockaddr *) &where, sizeof(where)) < 0) { /* couldn't connect. We'll have to launch this guy. */ unlink (where.sun_path); /* fork and launch call manager process */ switch (pid = fork()) { case -1: /* failure */ fatal("fork() to launch call manager failed."); case 0: /* child */ { close (fd); /* close the pty and gre in the call manager */ close(pty_fd); close(gre_fd); launch_callmgr(inetaddr, phonenr, argc, argv, envp); } default: /* parent */ waitpid(pid, &status, 0); if (status!= 0) fatal("Call manager exited with error %d", status); break; } sleep(1); } else return fd; } close(fd); fatal("Could not launch call manager after %d tries.", i); return -1; /* make gcc happy */}/*** call the call manager main ***********************************************/void launch_callmgr(struct in_addr inetaddr, char *phonenr, int argc, char**argv,char**envp) { char *my_argv[3] = { argv[0], inet_ntoa(inetaddr), phonenr }; char buf[128]; snprintf(buf, sizeof(buf), "pptp: call manager for %s", my_argv[1]); inststr(argc, argv, envp, buf); exit(callmgr_main(3, my_argv, envp));}/*** exchange data with the call manager *************************************//* XXX need better error checking XXX */int get_call_id(int sock, pid_t gre, pid_t pppd, u_int16_t *call_id, u_int16_t *peer_call_id){ u_int16_t m_call_id, m_peer_call_id; /* write pid's to socket */ /* don't bother with network byte order, because pid's are meaningless * outside the local host. */ int rc; rc = write(sock, &gre, sizeof(gre)); if (rc != sizeof(gre)) return -1; rc = write(sock, &pppd, sizeof(pppd)); if (rc != sizeof(pppd)) return -1; rc = read(sock, &m_call_id, sizeof(m_call_id)); if (rc != sizeof(m_call_id)) return -1; rc = read(sock, &m_peer_call_id, sizeof(m_peer_call_id)); if (rc != sizeof(m_peer_call_id)) return -1; /* * XXX FIXME ... DO ERROR CHECKING & TIME-OUTS XXX * (Rhialto: I am assuming for now that timeouts are not relevant * here, because the read and write calls would return -1 (fail) when * the peer goes away during the process. We know it is (or was) * running because the connect() call succeeded.) * (James: on the other hand, if the route to the peer goes away, we * wouldn't get told by read() or write() for quite some time.) */ *call_id = m_call_id; *peer_call_id = m_peer_call_id; return 0;}/*** execvp pppd **************************************************************/void launch_pppd(char *ttydev, int argc, char **argv){ char *new_argv[argc + 4];/* XXX if not using GCC, hard code a limit here. */ int i = 0, j; new_argv[i++] = PPPD_BINARY;#ifdef USER_PPP new_argv[i++] = "-direct"; /* ppp expects to have stdin connected to ttydev */ if ((j = open(ttydev, O_RDWR)) == -1) fatal("Cannot open %s: %s", ttydev, strerror(errno)); if (dup2(j, 0) == -1) fatal("dup2 failed: %s", strerror(errno)); close(j);#else new_argv[i++] = ttydev; new_argv[i++] = "38400";#endif for (j = 0; j < argc; j++) new_argv[i++] = argv[j]; new_argv[i] = NULL; execvp(new_argv[0], new_argv);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -