pptp-1.8.0/0000775000175000017500000000000012231702206011460 5ustar jamesjamespptp-1.8.0/util.h0000644000175000017500000000355612231702206012615 0ustar jamesjames/* util.h ....... error message utilities. * C. Scott Ananian * * $Id: util.h,v 1.8 2011/12/19 07:15:03 quozl Exp $ */ #ifndef INC_UTIL_H #define INC_UTIL_H /* log_string is an identifier for this pptp process, passed from command line using --log-string=X, and included with every log message. Useful for people with multiple pptp sessions open at a time */ extern const char * log_string; /* log_level sets the logging verbosity. Values range from 0 (errors only) to 1 (errors and warnings) to 2 (high verbosity, for debugging) */ extern int log_level; void _log(const char *func, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 4, 5))); void _warn(const char *func, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 4, 5))); void _fatal(const char *func, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 4, 5))) __attribute__ ((noreturn)); #define log(format, args...) \ _log(__FUNCTION__,__FILE__,__LINE__, format , ## args) #define warn(format, args...) \ _warn(__FUNCTION__,__FILE__,__LINE__, format , ## args) #define fatal(format, args...) \ _fatal(__FUNCTION__,__FILE__,__LINE__, format , ## args) int file2fd(const char *path, const char *mode, int fd); /* signal to pipe delivery implementation */ /* create a signal pipe, returns 0 for success, -1 with errno for failure */ int sigpipe_create(void); /* generic handler for signals, writes signal number to pipe */ void sigpipe_handler(int signum); /* assign a signal number to the pipe */ void sigpipe_assign(int signum); /* return the signal pipe read file descriptor for select(2) */ int sigpipe_fd(void); /* read and return the pending signal from the pipe */ int sigpipe_read(void); void sigpipe_close(void); #endif /* INC_UTIL_H */ pptp-1.8.0/routing.h0000644000175000017500000000044612231702206013322 0ustar jamesjames#if defined (__SVR4) && defined (__sun) /* Solaris */ #include #include struct rt_msg { struct rt_msghdr hdr; struct sockaddr_in addrs[RTAX_MAX]; }; #endif /* Solaris */ void routing_init(char *ip); void routing_start(void); void routing_end(void); pptp-1.8.0/pptpsetup0000644000175000017500000001600612231702206013450 0ustar jamesjames#!/usr/bin/perl use strict; use Getopt::Long; use vars qw($VERSION); $VERSION = '0.03'; # Command-line parameters: # actions my ( $_create, $_delete, $_help ); # values my ( $SERVER, $DOMAIN, $USERNAME, $PASSWORD, $ENCRYPT, $START ); my $result = GetOptions( "create|c=s" => \$_create, # --create foo -> &create("foo") "delete=s" => \$_delete, # --delete foo -> &delete("foo") "help|h" => \$_help, # --help -> &help() "server|s=s" => \$SERVER, "domain|d=s" => \$DOMAIN, "username|u=s" => \$USERNAME, "password|p=s" => \$PASSWORD, "encrypt|e" => \$ENCRYPT, "start" => \$START, ); if ($_create) { &create($_create); } elsif ($_delete) { &delete($_delete); } elsif ($_help) { &help(); } else { die "$0: too few arguments.\nTry '$0 --help' for more information.\n"; } exit; #### sub create { my $TUNNEL = shift; # if encryption is requested, check for support in kernel and pppd if ( $ENCRYPT ) { &Check_MPPE_in_kernel or die "$0: couldn't find MPPE support in kernel.\n"; &Check_MPPE_in_pppd or die "$0: couldn't find MPPE support in pppd.\n"; } # input validation ($TUNNEL) = $TUNNEL =~ m{^(\w+)$} or die "$0: invalid tunnel name.\nTry '$0 --help' for more information.\n"; ($SERVER) = $SERVER =~ m{^(.+)$} or die "$0: invalid server.\nTry '$0 --help' for more information.\n"; ($USERNAME) = $USERNAME =~ m{^(.+)$} or die "$0: invalid username.\nTry '$0 --help' for more information.\n"; # ask password if ( !$PASSWORD ) { print "Password: "; $PASSWORD = ; chomp $PASSWORD; } # put '\' between domain and username IF specified a domain $DOMAIN = "$DOMAIN\\" if $DOMAIN; # create or add lines to the /etc/ppp/chap-secrets file, # which holds usernames and passwords my $chap_secrets_file = '/etc/ppp/chap-secrets'; open( FILE, ">>$chap_secrets_file" ) or die "$0: can't write to '$chap_secrets_file': $!\n"; print FILE "\n# added by pptpsetup for $TUNNEL\n$DOMAIN$USERNAME $TUNNEL \"$PASSWORD\" *\n"; close FILE; # create a /etc/ppp/peers/$TUNNEL file my $tunnel_file = "/etc/ppp/peers/$TUNNEL"; open( FILE, ">$tunnel_file" ) or die "$0: can't write to '$tunnel_file': $!\n"; print FILE <<"TUNNEL"; # written by pptpsetup pty "pptp $SERVER --nolaunchpppd" lock noauth nobsdcomp nodeflate name $DOMAIN$USERNAME remotename $TUNNEL ipparam $TUNNEL TUNNEL print FILE "require-mppe-128\n" if $ENCRYPT; close FILE; # start tunneling if ($START) { system("pppd call $TUNNEL updetach"); } } #### sub help { print <<'EOF'; pptpsetup --create --server [--domain ] --username [--password ] [--encrypt] [--start] pptpsetup --delete Options: * the name you wish to use to refer to the tunnel (you choose it), * the IP address or host name of the server, * the authentication domain name (optional), * the username you are to use, * the password you are to use, * whether encryption is required, * whether to start the connection after configuration. pptpsetup - Point-to-Point Tunneling Protocol setup Copyright (C) 2006 Nelson Ferraz pptpsetup comes with ABSOLUTELY NO WARRANTY; for details see source. This is free software, and you are welcome to redistribute it under certain conditions; see source for details. EOF exit; } #### sub delete { my $tunnel = shift; # input validation ($tunnel) = $tunnel =~ m{^(\w+)$} or die "$0: invalid tunnel name.\nTry '$0 --help' for more information.\n"; # delete tunnel file my $tunnel_file = "/etc/ppp/peers/$tunnel"; unlink $tunnel_file or die "$0: can't delete '$tunnel_file': $!\n"; # delete entry from chap-secrets my $chap_file = '/etc/ppp/chap-secrets'; my $mode = (stat($chap_file))[2] & 07777; open( FILE, $chap_file ) or die "$0: can't read '$chap_file': $!\n"; my @chap = ; close FILE; my $new_chap = ''; foreach (@chap) { $new_chap .= $_ unless /\b$tunnel\b/; } # backup rename( $chap_file, "$chap_file.bkp" ); # write new chap-secrets open( FILE, ">$chap_file" ) or die "$0: can't write '$chap_file': $!\n"; chmod $mode, $chap_file; print FILE $new_chap; close FILE; exit; } ### AUXILIAR SUBS ### sub Check_MPPE_in_kernel { my $command = q/modprobe ppp-compress-18/; if (system( $command ) == 0) { # no error! return 1; } else { return 0; } } sub Check_MPPE_in_pppd { my $command = q/strings `which pppd`|grep -i mppe|wc --lines/; my $answer = `$command`; if ($answer > 0) { # ok! return 1; } else { return 0; } } __END__ =head1 NAME pptpsetup - Point-to-Point Tunneling Protocol setup =head1 SYNOPSIS pptpsetup --create --server [--domain ] --username [--password ] [--encrypt] [--start] pptpsetup --delete =head1 DESCRIPTION PPTP Client is a Linux, FreeBSD, NetBSD and OpenBSD client for the proprietary Microsoft Point-to-Point Tunneling Protocol, PPTP. This script configures PPTP Client on Linux. =head1 OPTIONS =over 16 =item --create TUNNEL create a tunnel named TUNNEL =item --delete TUNNEL delete the file /etc/ppp/peers/TUNNEL and any lines from /etc/ppp/chap-secrets that contains "TUNNEL" as a single word =item --server SERVER the IP address or host name of the server =item --domain DOMAIN the authentication domain name (optional) =item --username USERNAME the username you are to use =item --password PASSWORD the password you are to use. If you don't specify a password, pptpsetup will ask for one. =item --encrypt whether encryption is required =item --start whether the connection should be started after configuration. =back =head1 AUTHOR Nelson Ferraz , based on James Cameron's PPTP Client Debian HOWTO. =head1 SEE ALSO =over 16 =item PPTP Client Debian HOWTO http://pptpclient.sourceforge.net/howto-debian.phtml =item PPTP Client Diagnosis HOWTO http://pptpclient.sourceforge.net/howto-diagnosis.phtml =back =head1 COPYRIGHT pptpsetup - Point-to-Point Tunneling Protocol setup Copyright (C) 2006 Nelson Ferraz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA pptp-1.8.0/vector.c0000644000175000017500000001372612231702206013135 0ustar jamesjames/* vector.c ..... store a vector of PPTP_CALL information and search it * efficiently. * C. Scott Ananian * * $Id: vector.c,v 1.4 2011/12/19 07:15:03 quozl Exp $ */ #include #include #include #include "pptp_ctrl.h" #include "vector.h" /* #define VECTOR_DEBUG */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif struct vector_item { int key; PPTP_CALL *call; }; struct vector_struct { struct vector_item *item; int size; int alloc; #ifdef VECTOR_DEBUG int key_max; #endif }; static struct vector_item *binary_search(VECTOR *v, int key); /*** vector_create ************************************************************/ VECTOR *vector_create(void) { const int INITIAL_SIZE = 4; VECTOR *v = malloc(sizeof(*v)); if (v == NULL) return v; v->size = 0; v->alloc = INITIAL_SIZE; v->item = malloc(sizeof(*(v->item)) * (v->alloc)); #ifdef VECTOR_DEBUG v->key_max = -1; #endif if (v->item == NULL) { free(v); return NULL; } else return v; } /*** vector_destroy ***********************************************************/ void vector_destroy(VECTOR *v) { free(v->item); #ifdef VECTOR_DEBUG v->item = NULL; #endif free(v); } /*** vector_size **************************************************************/ int vector_size(VECTOR *v) { assert(v != NULL); return v->size; } /*** vector_insert************************************************************* * nice thing about file descriptors is that we are assured by POSIX * that they are monotonically increasing. */ int vector_insert(VECTOR *v, int key, PPTP_CALL * call) { int i; assert(v != NULL && call != NULL); assert(!vector_contains(v, key)); #ifdef VECTOR_DEBUG assert(v->key_max < key); #endif if (!(v->size < v->alloc)) { void *tmp = realloc(v->item, sizeof(*(v->item)) * 2 * v->alloc); if (tmp != NULL) { v->alloc *= 2; v->item = tmp; } else return FALSE; /* failed to alloc memory. */ } assert(v->size < v->alloc); /* for safety, we make this work in the general case; * but this is optimized for adding call to the end of the vector. */ for(i = v->size - 1; i >= 0; i--) if (v->item[i].key < key) break; /* insert after item i */ memmove(&v->item[i + 2], &v->item[i + 1], (v->size - i - 1) * sizeof(*(v->item))); v->item[i + 1].key = key; v->item[i + 1].call = call; v->size++; #ifdef VECTOR_DEBUG if (v->key_max < key) /* ie, always. */ v->key_max = key; #endif return TRUE; } /*** vector_remove ************************************************************/ int vector_remove(VECTOR *v, int key) { struct vector_item *tmp; assert(v != NULL); if ((tmp =binary_search(v,key)) == NULL) return FALSE; assert(tmp >= v->item && tmp < v->item + v->size); memmove(tmp, tmp + 1, (v->size - (v->item - tmp) - 1) * sizeof(*(v->item))); v->size--; return TRUE; } /*** vector_search ************************************************************/ int vector_search(VECTOR *v, int key, PPTP_CALL **call) { struct vector_item *tmp; assert(v != NULL); tmp = binary_search(v, key); if (tmp ==NULL) return FALSE; *call = tmp->call; return TRUE; } /*** vector_contains **********************************************************/ int vector_contains(VECTOR *v, int key) { assert(v != NULL); return (binary_search(v, key) != NULL); } /*** vector_item **************************************************************/ static struct vector_item *binary_search(VECTOR *v, int key) { int l,r,x; l = 0; r = v->size - 1; while (r >= l) { x = (l + r)/2; if (key < v->item[x].key) r = x - 1; else l = x + 1; if (key == v->item[x].key) return &(v->item[x]); } return NULL; } /*** vector_scan *************************************************************** * Hmm. Let's be fancy and use a binary search for the first * unused key, taking advantage of the list is stored sorted; ie * we can look at pointers and keys at two different locations, * and if (ptr1 - ptr2) = (key1 - key2) then all the slots * between ptr1 and ptr2 are filled. Note that ptr1-ptr2 should * never be greater than key1-key2 (no duplicate keys!)... we * check for this. */ int vector_scan(VECTOR *v, int lo, int hi, int *key) { int l,r,x; assert(v != NULL); assert(key != NULL); if ((v->size<1) || (lo < v->item[0].key)) { *key = lo; return TRUE; } /* our array bounds */ l = 0; r = v->size - 1; while (r > l) { /* check for a free spot right after l */ if (v->item[l].key + 1 < v->item[l + 1].key) { /* found it! */ *key = v->item[l].key + 1; return TRUE; } /* no dice. Let's see if the free spot is before or after the midpoint */ x = (l + r)/2; /* Okay, we have right (r), left (l) and the probe (x). */ assert(x - l <= v->item[x].key - v->item[l].key); assert(r - x <= v->item[r].key - v->item[x].key); if (x - l < v->item[x].key - v->item[l].key) /* room between l and x */ r = x; else /* no room between l and x */ if (r - x < v->item[r].key - v->item[x].key) /* room between x and r */ l = x; else /* no room between x and r, either */ break; /* game over, man. */ } /* no room found in already allocated space. Check to see if * there's free space above allocated entries. */ if (v->item[v->size - 1].key < hi) { *key = v->item[v->size - 1].key + 1; return TRUE; } /* outta luck */ return FALSE; } /*** vector_get_Nth ***********************************************************/ PPTP_CALL * vector_get_Nth(VECTOR *v, int n) { assert(v != NULL); assert(0 <= n && n < vector_size(v)); return v->item[n].call; } pptp-1.8.0/pptp_ctrl.h0000644000175000017500000000456312231702206013646 0ustar jamesjames/* pptp_ctrl.h ... handle PPTP control connection. * C. Scott Ananian * * $Id: pptp_ctrl.h,v 1.7 2010/06/15 05:04:32 quozl Exp $ */ #ifndef INC_PPTP_CTRL_H #define INC_PPTP_CTRL_H #include #include "pptp_compat.h" typedef struct PPTP_CONN PPTP_CONN; typedef struct PPTP_CALL PPTP_CALL; enum call_state { CALL_OPEN_RQST, CALL_OPEN_DONE, CALL_OPEN_FAIL, CALL_CLOSE_RQST, CALL_CLOSE_DONE }; enum conn_state { CONN_OPEN_RQST, CONN_OPEN_DONE, CONN_OPEN_FAIL, CONN_CLOSE_RQST, CONN_CLOSE_DONE }; typedef void (*pptp_call_cb)(PPTP_CONN*, PPTP_CALL*, enum call_state); typedef void (*pptp_conn_cb)(PPTP_CONN*, enum conn_state); /* if 'isclient' is true, then will send 'conn open' packet to other host. * not necessary if this is being opened by a server process after * receiving a conn_open packet from client. */ PPTP_CONN * pptp_conn_open(int inet_sock, int isclient, pptp_conn_cb callback); PPTP_CALL * pptp_call_open(PPTP_CONN * conn, pptp_call_cb callback, char *phonenr); int pptp_conn_established(PPTP_CONN * conn); /* soft close. Will callback on completion. */ void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call); /* hard close. */ void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call); int pptp_conn_is_dead(PPTP_CONN * conn); void pptp_conn_free(PPTP_CONN * conn); /* soft close. Will callback on completion. */ void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason); /* hard close */ void pptp_conn_destroy(PPTP_CONN * conn); /* Add file descriptors used by pptp to fd_set. */ void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set, int *max_fd); /* handle any pptp file descriptors set in fd_set, and clear them */ int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set); /* Get info about connection, call */ void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call, u_int16_t * call_id, u_int16_t * peer_call_id); /* Arbitrary user data about this call/connection. * It is the caller's responsibility to free this data before calling * pptp_call|conn_close() */ void * pptp_conn_closure_get(PPTP_CONN * conn); void pptp_conn_closure_put(PPTP_CONN * conn, void *cl); void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call); void pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl); #endif /* INC_PPTP_CTRL_H */ pptp-1.8.0/NEWS0000644000175000017500000001306212231702206012157 0ustar jamesjamesRelease 1.8.0: (23rd October 2013) - options file, fix option documentation and links [Howarth] - fix many warnings [Howarth] - fix parallel build failure [Howarth] - fix call disconnect notify [Howarth] - add --nohostroute option to disable routing calls [Lamparter] - add --rtmark option for Linux policy routing [Lamparter] - move free of conn struct out of main loop [Cameron] - avoid using conn struct after it is freed [Keijser] - correct response to call disconnect notify [Shen] - avoid superfluous MPPE capability checks in pptpsetup [Howarth] - retain permissions on chap-secrets, closes RH BZ #492090 [Howarth] - compilation fixes for older distributions of Linux [Howarth] - port routing change feature for Solaris [Voronin] - add IP_BINARY [Cameron] - add include file build dependencies [Cameron] Release 1.7.2: (14th May 2008) - port for Solaris 10/11 [Voronin] - make copyright and license clearer [Cameron/Ananian] - add packet reordering test code for pptpd testing [Cameron] - ignore transient send errors [Adda] - fix flaw in return status check of select in GRE pipe (possibly fixes Debian Bug #427586) [Cameron] - add route to PPTP server [Cameron] - remove non-free reference documentation [Cameron] - fix quoting and pppd options [Lundqvist] - pptpsetup script with man page (Debian Bug #167216) [Ferraz] Release 1.7.1: (13th February 2006) - use prctl(2) to set process name [Cameron] - add --version option [Cameron] - remove superfluous sigset [Cameron/Gono] - default options file to not require MPPE (#166394) [Howarth] - add PROTOCOL-SECURITY discussion [Cameron/Mueller] Release 1.7.0: (27th July 2005) - silently discard packets not for the call [Cameron/Jenkins] - adopt sigpipe for use with SIGALRM on control connection [Wolter/Cameron] - fixes known valgrind heap violations in 1.6.0 [Cameron/Thorne] - properly report control connection echo reply loss [Wolter] Release 1.6.0: (18th February 2005) - fix double-free on stop control connection reply [Kivity] - add --idle-wait option [Cameron] - fix segfault on fatal connection error [Kivity] - prevent a possible signal race [Kivity] - prevent kill of init [Shurdeek] - portability fix for non-Linux systems [Quinot] - rename package from pptp-linux to pptp [Cameron] Release 1.5.0: (22nd June 2004) - fix statistics when buffering disabled [Wilson] - do not inherit the GRE socket [Cameron] - fix a case of non-shutdown of call manager [Klazes] - add --nobuffer option to eliminate all buffering of packets [Wilson] - fix corruption of command line as shown by ps [Howarth] - fix CPU loop after pppd killed [Cameron] - fix compile for ARM architecture [Hopf] - add documentation for command-line options [Wilson] - do not hang when a connection is refused [McCurdy] - better describe a cause of EMSGSIZE [Cameron] Release 1.4.0: (2nd January 2004) - support options before hostname [Wilson] - defer OCRQ until after SCCRP [Cameron] - include uninstall target [Pieter] - only issue a warning if sync mode is different to pppd [Klazes] - reformat and tidy code [Klazes] - reduce transmitted ack-only packets from 40% to 0.8% [Klazes] Release 1.3.1: (11th June 2003) - fixed bug introduced since 1.2.0 that prevented simultaneous tunnels. Release 1.3.0: (10th June 2003) - rewrite command usage text. - increase call disconnect notification log message verbosity. - inherit more make command line options. - remove execute permissions on man page. - fixed inefficient acknowledgement immediately followed by data packet. - added statistics for link quality monitoring. - remove include of callmgr, do separate compile. - remove duplicate messages caused by code in header file. - compilation fixes for Apple MacOS X. - support multiple clients on alias IP addresses. Release 1.2.0: (14th February 2003) - subsecond packet timeout to improve performance on fast links. - rewrite INSTALL. - add man page to install target. - fix response to dropped packets. - fix man page, address must be before options. - adopt man page contributed by Thomas Quinot. - close stderr to prevent holding open ssh sessions. - minor hint added in case of EIO on read() of pty. - support synchronous HDLC ppp encoding. Synchronous mode results in an important improvement of the CPU efficiency. - handle out-of-order packets arriving on the GRE socket by buffering. - bind GRE socket early to prevent ICMP Unreachable response by client. Release 1.1.0: (20th March 2002) - New release engineer. - allow activation as a psuedo-tty child process from pppd. This allows on demand pptp links or automatically reconnect. - ADSL modem quirks handler by mulix@actcom.co.il. Workarounds for Orckit ADSL modem. - workaround for Cisco PIX connection drop after 60 seconds. - enhance bad FCS error message. - ported to FreeBSD and NetBSD. - integrated call manager into pptp binary. - many bugfixes improving stability. Release 1.0.3: (7th May 2001) - New maintaining team. - Various bug fixes from the Debian package and FreeBSD port. - Incorporate patch to support erroneous return code with Alcatel ADSL 1000 modems. - Fix incorrect call id error. - New command line option: --phone (specify phone number). (Needed by the Dutch Mxstream ADSL service.) Contributed by Rein Klazes Release 1.0.2: - Fixed some warnings. - glibc patches by Christoph Lameter - Race condition fix by Gordon Chaffee Release 1.0.1: - Added versioning information to sources and makefile. - Bugfixes to pptp_ctrl.c. Release 1.0.0: - This is the first public release of the pptp-linux package. $Id: NEWS,v 1.71 2011/11/29 22:05:07 quozl Exp $ pptp-1.8.0/pptp_ctrl.c0000644000175000017500000012555512231702206013646 0ustar jamesjames/* pptp_ctrl.c ... handle PPTP control connection. * C. Scott Ananian * * $Id: pptp_ctrl.c,v 1.40 2011/12/19 07:15:03 quozl Exp $ */ #include #if defined (__SVR4) && defined (__sun) /* Solaris */ #define _XPG4_2 #define __EXTENSIONS__ #endif /* Solaris */ #include #include #include #include #include #include #include #include #include #include #include #include "pptp_msg.h" #include "pptp_ctrl.h" #include "pptp_options.h" #include "vector.h" #include "util.h" #include "pptp_quirks.h" /* BECAUSE OF SIGNAL LIMITATIONS, EACH PROCESS CAN ONLY MANAGE ONE * CONNECTION. SO THIS 'PPTP_CONN' STRUCTURE IS A BIT MISLEADING. * WE'LL KEEP CONNECTION-SPECIFIC INFORMATION IN THERE ANYWAY (AS * OPPOSED TO USING GLOBAL VARIABLES), BUT BEWARE THAT THE ENTIRE * UNIX SIGNAL-HANDLING SEMANTICS WOULD HAVE TO CHANGE (OR THE * TIME-OUT CODE DRASTICALLY REWRITTEN) BEFORE YOU COULD DO A * PPTP_CONN_OPEN MORE THAN ONCE PER PROCESS AND GET AWAY WITH IT. */ /* This structure contains connection-specific information that the * signal handler needs to see. Thus, it needs to be in a global * variable. If you end up using pthreads or something (why not * just processes?), this would have to be placed in a thread-specific * data area, using pthread_get|set_specific, etc., so I've * conveniently encapsulated it for you. * [linux threads will have to support thread-specific signals * before this would work at all, which, as of this writing * (linux-threads v0.6, linux kernel 2.1.72), it does not.] */ /* Globals */ /* control the number of times echo packets will be logged */ static int nlogecho = 10; static struct thread_specific { struct sigaction old_sigaction; /* evil signals */ PPTP_CONN * conn; } global; #define INITIAL_BUFSIZE 512 /* initial i/o buffer size. */ struct PPTP_CONN { int inet_sock; /* Connection States */ enum { CONN_IDLE, CONN_WAIT_CTL_REPLY, CONN_WAIT_STOP_REPLY, CONN_ESTABLISHED, CONN_DEAD } conn_state; /* on startup: CONN_IDLE */ /* Keep-alive states */ enum { KA_NONE, KA_OUTSTANDING } ka_state; /* on startup: KA_NONE */ /* Keep-alive ID; monotonically increasing (watch wrap-around!) */ u_int32_t ka_id; /* on startup: 1 */ /* Other properties. */ u_int16_t version; u_int16_t firmware_rev; u_int8_t hostname[64], vendor[64]; /* XXX these are only PNS properties, currently XXX */ /* Call assignment information. */ u_int16_t call_serial_number; VECTOR *call; void * closure; pptp_conn_cb callback; /******* IO buffers ******/ char * read_buffer, *write_buffer; size_t read_alloc, write_alloc; size_t read_size, write_size; }; struct PPTP_CALL { /* Call properties */ enum { PPTP_CALL_PAC, PPTP_CALL_PNS } call_type; union { enum pptp_pac_state { PAC_IDLE, PAC_WAIT_REPLY, PAC_ESTABLISHED, PAC_WAIT_CS_ANS } pac; enum pptp_pns_state { PNS_IDLE, PNS_WAIT_REPLY, PNS_ESTABLISHED, PNS_WAIT_DISCONNECT } pns; } state; u_int16_t call_id, peer_call_id; u_int16_t sernum; u_int32_t speed; /* For user data: */ pptp_call_cb callback; void * closure; }; /* PPTP error codes: ----------------------------------------------*/ /* (General Error Codes) */ static const struct { const char *name, *desc; } pptp_general_errors[] = { #define PPTP_GENERAL_ERROR_NONE 0 { "(None)", "No general error" }, #define PPTP_GENERAL_ERROR_NOT_CONNECTED 1 { "(Not-Connected)", "No control connection exists yet for this " "PAC-PNS pair" }, #define PPTP_GENERAL_ERROR_BAD_FORMAT 2 { "(Bad-Format)", "Length is wrong or Magic Cookie value is incorrect" }, #define PPTP_GENERAL_ERROR_BAD_VALUE 3 { "(Bad-Value)", "One of the field values was out of range or " "reserved field was non-zero" }, #define PPTP_GENERAL_ERROR_NO_RESOURCE 4 { "(No-Resource)", "Insufficient resources to handle this command now" }, #define PPTP_GENERAL_ERROR_BAD_CALLID 5 { "(Bad-Call ID)", "The Call ID is invalid in this context" }, #define PPTP_GENERAL_ERROR_PAC_ERROR 6 { "(PAC-Error)", "A generic vendor-specific error occured in the PAC" } }; #define MAX_GENERAL_ERROR ( sizeof(pptp_general_errors) / \ sizeof(pptp_general_errors[0]) - 1) /* Outgoing Call Reply Result Codes */ static const char *pptp_out_call_reply_result[] = { /* 0 */ "Unknown Result Code", /* 1 */ "Connected", /* 2 */ "General Error", /* 3 */ "No Carrier Detected", /* 4 */ "Busy Signal", /* 5 */ "No Dial Tone", /* 6 */ "Time Out", /* 7 */ "Not Accepted, Call is administratively prohibited" }; #define MAX_OUT_CALL_REPLY_RESULT 7 /* Call Disconnect Notify Result Codes */ static const char *pptp_call_disc_ntfy[] = { /* 0 */ "Unknown Result Code", /* 1 */ "Lost Carrier", /* 2 */ "General Error", /* 3 */ "Administrative Shutdown", /* 4 */ "(your) Request" }; #define MAX_CALL_DISC_NTFY 4 /* Call Disconnect Notify Result Codes */ static const char *pptp_start_ctrl_conn_rply[] = { /* 0 */ "Unknown Result Code", /* 1 */ "Successful Channel Establishment", /* 2 */ "General Error", /* 3 */ "Command Channel Already Exists", /* 4 */ "Requester is not Authorized" }; #define MAX_START_CTRL_CONN_REPLY 4 /* timing options */ int idle_wait = PPTP_TIMEOUT; int max_echo_wait = PPTP_TIMEOUT; /* Local prototypes */ static void pptp_reset_timer(void); static void pptp_handle_timer(void); /* Write/read as much as we can without blocking. */ int pptp_write_some(PPTP_CONN * conn); int pptp_read_some(PPTP_CONN * conn); /* Make valid packets from read_buffer */ int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size); /* Add packet to write_buffer */ int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size); /* Dispatch packets (general) */ int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size); /* Dispatch packets (control messages) */ int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size); /* Set link info, for pptp servers that need it. this is a noop, unless the user specified a quirk and there's a set_link hook defined in the quirks table for that quirk */ void pptp_set_link(PPTP_CONN * conn, int peer_call_id); /*** log error information in control packets *********************************/ static void ctrlp_error( int result, u_int8_t error, int cause, const char *result_text[], int max_result) { if( cause >= 0) log("Result code is %d '%s'. Error code is %d, Cause code is %d", result, result_text[result <= max_result ? result : 0], error, cause ); else log("Reply result code is %d '%s'. Error code is %d", result, result_text[result <= max_result ? result : 0], error); if ((error > 0) && (error <= MAX_GENERAL_ERROR)){ if( result != PPTP_RESULT_GENERAL_ERROR ) log("Result code is something else then \"general error\", " "so the following error is probably bogus."); log("Error is '%s', Error message: '%s'", pptp_general_errors[error].name, pptp_general_errors[error].desc); } } static const char *ctrl_msg_types[] = { "invalid control message type", /* (Control Connection Management) */ "Start-Control-Connection-Request", /* 1 */ "Start-Control-Connection-Reply", /* 2 */ "Stop-Control-Connection-Request", /* 3 */ "Stop-Control-Connection-Reply", /* 4 */ "Echo-Request", /* 5 */ "Echo-Reply", /* 6 */ /* (Call Management) */ "Outgoing-Call-Request", /* 7 */ "Outgoing-Call-Reply", /* 8 */ "Incoming-Call-Request", /* 9 */ "Incoming-Call-Reply", /* 10 */ "Incoming-Call-Connected", /* 11 */ "Call-Clear-Request", /* 12 */ "Call-Disconnect-Notify", /* 13 */ /* (Error Reporting) */ "WAN-Error-Notify", /* 14 */ /* (PPP Session Control) */ "Set-Link-Info" /* 15 */ }; #define MAX_CTRLMSG_TYPE 15 /*** report a sent packet ****************************************************/ static void ctrlp_rep( void * buffer, size_t size, int isbuff) { struct pptp_header *packet = buffer; unsigned int type; if(size < sizeof(struct pptp_header)) return; type = ntoh16(packet->ctrl_type); /* FIXME: do not report sending echo requests as long as they are * sent in a signal handler. This may dead lock as the syslog call * is not reentrant */ if( type == PPTP_ECHO_RQST ) return; /* don't keep reporting sending of echo's */ if( (type == PPTP_ECHO_RQST || type == PPTP_ECHO_RPLY) && nlogecho <= 0 ) return; log("%s control packet type is %d '%s'\n",isbuff ? "Buffered" : "Sent", type, ctrl_msg_types[type <= MAX_CTRLMSG_TYPE ? type : 0]); } /* Open new pptp_connection. Returns NULL on failure. */ PPTP_CONN * pptp_conn_open(int inet_sock, int isclient, pptp_conn_cb callback) { PPTP_CONN *conn; /* Allocate structure */ if ((conn = malloc(sizeof(*conn))) == NULL) return NULL; if ((conn->call = vector_create()) == NULL) { free(conn); return NULL; } /* Initialize */ conn->inet_sock = inet_sock; conn->conn_state = CONN_IDLE; conn->ka_state = KA_NONE; conn->ka_id = 1; conn->call_serial_number = 0; conn->callback = callback; /* Create I/O buffers */ conn->read_size = conn->write_size = 0; conn->read_alloc = conn->write_alloc = INITIAL_BUFSIZE; conn->read_buffer = malloc(sizeof(*(conn->read_buffer)) * conn->read_alloc); conn->write_buffer = malloc(sizeof(*(conn->write_buffer)) * conn->write_alloc); if (conn->read_buffer == NULL || conn->write_buffer == NULL) { if (conn->read_buffer != NULL) free(conn->read_buffer); if (conn->write_buffer != NULL) free(conn->write_buffer); vector_destroy(conn->call); free(conn); return NULL; } /* Make this socket non-blocking. */ fcntl(conn->inet_sock, F_SETFL, O_NONBLOCK); /* Request connection from server, if this is a client */ if (isclient) { struct pptp_start_ctrl_conn packet = { PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RQST), hton16(PPTP_VERSION), 0, 0, hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP), hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION), PPTP_HOSTNAME, PPTP_VENDOR }; /* fix this packet, if necessary */ int idx, rc; idx = get_quirk_index(); if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) { if ((rc = pptp_fixups[idx].start_ctrl_conn(&packet))) warn("calling the start_ctrl_conn hook failed (%d)", rc); } if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) conn->conn_state = CONN_WAIT_CTL_REPLY; else return NULL; /* could not send initial start request. */ } /* Set up interval/keep-alive timer */ /* First, register handler for SIGALRM */ sigpipe_create(); sigpipe_assign(SIGALRM); global.conn = conn; /* Reset event timer */ pptp_reset_timer(); /* all done. */ return conn; } int pptp_conn_established(PPTP_CONN *conn) { return (conn->conn_state == CONN_ESTABLISHED); } /* This currently *only* works for client call requests. * We need to do something else to allocate calls for incoming requests. */ PPTP_CALL * pptp_call_open(PPTP_CONN * conn, pptp_call_cb callback, char *phonenr) { PPTP_CALL * call; int i; int idx, rc; /* Send off the call request */ struct pptp_out_call_rqst packet = { PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST), 0,0, /*call_id, sernum */ hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX), hton32(PPTP_BEARER_CAP), hton32(PPTP_FRAME_CAP), hton16(PPTP_WINDOW), 0, 0, 0, {0}, {0} }; assert(conn && conn->call); assert(conn->conn_state == CONN_ESTABLISHED); /* Assign call id */ if (!vector_scan(conn->call, 0, PPTP_MAX_CHANNELS - 1, &i)) /* no more calls available! */ return NULL; /* allocate structure. */ if ((call = malloc(sizeof(*call))) == NULL) return NULL; /* Initialize call structure */ call->call_type = PPTP_CALL_PNS; call->state.pns = PNS_IDLE; call->call_id = (u_int16_t) i; call->sernum = conn->call_serial_number++; call->callback = callback; call->closure = NULL; packet.call_id = htons(call->call_id); packet.call_sernum = htons(call->sernum); /* if we have a quirk, build a new packet to fit it */ idx = get_quirk_index(); if (idx != -1 && pptp_fixups[idx].out_call_rqst_hook) { if ((rc = pptp_fixups[idx].out_call_rqst_hook(&packet))) warn("calling the out_call_rqst hook failed (%d)", rc); } /* fill in the phone number if it was specified */ if (phonenr) { strncpy((char *)packet.phone_num, phonenr, sizeof(packet.phone_num)); packet.phone_len = strlen(phonenr); if( packet.phone_len > sizeof(packet.phone_num)) packet.phone_len = sizeof(packet.phone_num); packet.phone_len = hton16 (packet.phone_len); } if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) { pptp_reset_timer(); call->state.pns = PNS_WAIT_REPLY; /* and add it to the call vector */ vector_insert(conn->call, i, call); return call; } else { /* oops, unsuccessful. Deallocate. */ free(call); return NULL; } } /*** pptp_call_close **********************************************************/ void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call) { struct pptp_call_clear_rqst rqst = { PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_RQST), 0, 0 }; assert(conn && conn->call); assert(call); assert(vector_contains(conn->call, call->call_id)); /* haven't thought about PAC yet */ assert(call->call_type == PPTP_CALL_PNS); assert(call->state.pns != PNS_IDLE); rqst.call_id = hton16(call->call_id); /* don't check state against WAIT_DISCONNECT... allow multiple disconnect * requests to be made. */ if (pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst))) { pptp_reset_timer(); call->state.pns = PNS_WAIT_DISCONNECT; } /* call structure will be freed when we have confirmation of disconnect. */ } /*** hard close ***************************************************************/ void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call) { assert(conn && conn->call); assert(call); assert(vector_contains(conn->call, call->call_id)); /* notify */ if (call->callback != NULL) call->callback(conn, call, CALL_CLOSE_DONE); /* deallocate */ vector_remove(conn->call, call->call_id); free(call); } /*** this is a soft close *****************************************************/ void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason) { struct pptp_stop_ctrl_conn rqst = { PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST), hton8(close_reason), 0, 0 }; int i; assert(conn && conn->call); /* avoid repeated close attempts */ if (conn->conn_state == CONN_IDLE || conn->conn_state == CONN_WAIT_STOP_REPLY) return; /* close open calls, if any */ for (i = 0; i < vector_size(conn->call); i++) pptp_call_close(conn, vector_get_Nth(conn->call, i)); /* now close connection */ log("Closing PPTP connection"); if (pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst))) { pptp_reset_timer(); /* wait 60 seconds for reply */ conn->conn_state = CONN_WAIT_STOP_REPLY; } return; } /*** this is a hard close *****************************************************/ void pptp_conn_destroy(PPTP_CONN * conn) { int i; assert(conn != NULL); assert(conn->call != NULL); /* destroy all open calls */ for (i = 0; i < vector_size(conn->call); i++) pptp_call_destroy(conn, vector_get_Nth(conn->call, i)); /* notify */ if (conn->callback != NULL) conn->callback(conn, CONN_CLOSE_DONE); sigpipe_close(); close(conn->inet_sock); /* deallocate */ vector_destroy(conn->call); conn->conn_state = CONN_DEAD; } int pptp_conn_is_dead(PPTP_CONN * conn) { return conn->conn_state == CONN_DEAD; } void pptp_conn_free(PPTP_CONN * conn) { free(conn); } /*** Deal with messages, in a non-blocking manner * Add file descriptors used by pptp to fd_set. */ void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set, int * max_fd) { int sig_fd; assert(conn && conn->call); /* Add fd to write_set if there are outstanding writes. */ if (conn->write_size > 0) FD_SET(conn->inet_sock, write_set); /* Always add fd to read_set. (always want something to read) */ FD_SET(conn->inet_sock, read_set); if (*max_fd < conn->inet_sock) *max_fd = conn->inet_sock; /* Add signal pipe file descriptor to set */ sig_fd = sigpipe_fd(); FD_SET(sig_fd, read_set); if (*max_fd < sig_fd) *max_fd = sig_fd; } /*** handle any pptp file descriptors set in fd_set, and clear them ***********/ int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set) { int r = 0; assert(conn && conn->call); /* Check for signals */ if (FD_ISSET(sigpipe_fd(), read_set)) { if (sigpipe_read() == SIGALRM) pptp_handle_timer(); FD_CLR(sigpipe_fd(), read_set); } /* Check write_set could be set. */ if (FD_ISSET(conn->inet_sock, write_set)) { FD_CLR(conn->inet_sock, write_set); if (conn->write_size > 0) r = pptp_write_some(conn);/* write as much as we can without blocking */ } /* Check read_set */ if (r >= 0 && FD_ISSET(conn->inet_sock, read_set)) { void *buffer; size_t size; FD_CLR(conn->inet_sock, read_set); r = pptp_read_some(conn); /* read as much as we can without blocking */ if (r < 0) return r; /* make packets of the buffer, while we can. */ while (r >= 0 && pptp_make_packet(conn, &buffer, &size)) { r = pptp_dispatch_packet(conn, buffer, size); free(buffer); } } /* That's all, folks. Simple, eh? */ return r; } /*** Non-blocking write *******************************************************/ int pptp_write_some(PPTP_CONN * conn) { ssize_t retval; assert(conn && conn->call); retval = write(conn->inet_sock, conn->write_buffer, conn->write_size); if (retval < 0) { /* error. */ if (errno == EAGAIN || errno == EINTR) { return 0; } else { /* a real error */ log("write error: %s", strerror(errno)); return -1; } } assert((size_t)retval <= conn->write_size); conn->write_size -= retval; memmove(conn->write_buffer, conn->write_buffer + retval, conn->write_size); ctrlp_rep(conn->write_buffer, retval, 0); return 0; } /*** Non-blocking read ********************************************************/ int pptp_read_some(PPTP_CONN * conn) { ssize_t retval; assert(conn && conn->call); if (conn->read_size == conn->read_alloc) { /* need to alloc more memory */ char *new_buffer = realloc(conn->read_buffer, sizeof(*(conn->read_buffer)) * conn->read_alloc * 2); if (new_buffer == NULL) { log("Out of memory"); return -1; } conn->read_alloc *= 2; conn->read_buffer = new_buffer; } retval = read(conn->inet_sock, conn->read_buffer + conn->read_size, conn->read_alloc - conn->read_size); if (retval == 0) { log("read returned zero, peer has closed"); return -1; } if (retval < 0) { if (errno == EINTR || errno == EAGAIN) return 0; else { /* a real error */ log("read error: %s", strerror(errno)); return -1; } } conn->read_size += retval; assert(conn->read_size <= conn->read_alloc); return 0; } /*** Packet formation *********************************************************/ int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size) { struct pptp_header *header; size_t bad_bytes = 0; assert(conn && conn->call); assert(buf != NULL); assert(size != NULL); /* Give up unless there are at least sizeof(pptp_header) bytes */ while ((conn->read_size-bad_bytes) >= sizeof(struct pptp_header)) { /* Throw out bytes until we have a valid header. */ header = (struct pptp_header *) (conn->read_buffer + bad_bytes); if (ntoh32(header->magic) != PPTP_MAGIC) goto throwitout; if (ntoh16(header->reserved0) != 0) log("reserved0 field is not zero! (0x%x) Cisco feature? \n", ntoh16(header->reserved0)); if (ntoh16(header->length) < sizeof(struct pptp_header)) goto throwitout; if (ntoh16(header->length) > PPTP_CTRL_SIZE_MAX) goto throwitout; /* well. I guess it's good. Let's see if we've got it all. */ if (ntoh16(header->length) > (conn->read_size-bad_bytes)) /* nope. Let's wait until we've got it, then. */ goto flushbadbytes; /* One last check: */ if ((ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL) && (ntoh16(header->length) != PPTP_CTRL_SIZE(ntoh16(header->ctrl_type)))) goto throwitout; /* well, I guess we've got it. */ *size = ntoh16(header->length); *buf = malloc(*size); if (*buf == NULL) { log("Out of memory."); return 0; /* ack! */ } memcpy(*buf, conn->read_buffer + bad_bytes, *size); /* Delete this packet from the read_buffer. */ conn->read_size -= (bad_bytes + *size); memmove(conn->read_buffer, conn->read_buffer + bad_bytes + *size, conn->read_size); if (bad_bytes > 0) log("%lu bad bytes thrown away.", (unsigned long) bad_bytes); return 1; throwitout: bad_bytes++; } flushbadbytes: /* no more packets. Let's get rid of those bad bytes */ conn->read_size -= bad_bytes; memmove(conn->read_buffer, conn->read_buffer + bad_bytes, conn->read_size); if (bad_bytes > 0) log("%lu bad bytes thrown away.", (unsigned long) bad_bytes); return 0; } /*** pptp_send_ctrl_packet ****************************************************/ int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size) { assert(conn && conn->call); assert(buffer); if( conn->write_size > 0) pptp_write_some( conn); if( conn->write_size == 0) { ssize_t retval; retval = write(conn->inet_sock, buffer, size); if (retval < 0) { /* error. */ if (errno == EAGAIN || errno == EINTR) { /* ignore */; retval = 0; } else { /* a real error */ log("write error: %s", strerror(errno)); pptp_conn_destroy(conn); /* shut down fast. */ return 0; } } ctrlp_rep( buffer, retval, 0); size -= retval; if( size <= 0) return 1; } /* Shove anything not written into the write buffer */ if (conn->write_size + size > conn->write_alloc) { /* need more memory */ char *new_buffer = realloc(conn->write_buffer, sizeof(*(conn->write_buffer)) * conn->write_alloc * 2); if (new_buffer == NULL) { log("Out of memory"); return 0; } conn->write_alloc *= 2; conn->write_buffer = new_buffer; } memcpy(conn->write_buffer + conn->write_size, buffer, size); conn->write_size += size; ctrlp_rep( buffer,size,1); return 1; } /*** Packet Dispatch **********************************************************/ int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size) { int r = 0; struct pptp_header *header = (struct pptp_header *)buffer; assert(conn && conn->call); assert(buffer); assert(ntoh32(header->magic) == PPTP_MAGIC); assert(ntoh16(header->length) == size); switch (ntoh16(header->pptp_type)) { case PPTP_MESSAGE_CONTROL: r = ctrlp_disp(conn, buffer, size); break; case PPTP_MESSAGE_MANAGE: /* MANAGEMENT messages aren't even part of the spec right now. */ log("PPTP management message received, but not understood."); break; default: log("Unknown PPTP control message type received: %u", (unsigned int) ntoh16(header->pptp_type)); break; } return r; } /*** log echo request/replies *************************************************/ static void logecho( int type) { /* hack to stop flooding the log files (the most interesting part is right * after the connection built-up) */ if( nlogecho > 0) { log( "Echo Re%s received.", type == PPTP_ECHO_RQST ? "quest" :"ply"); if( --nlogecho == 0) log("no more Echo Reply/Request packets will be reported."); } } /*** pptp_dispatch_ctrl_packet ************************************************/ int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size) { struct pptp_header *header = (struct pptp_header *)buffer; u_int8_t close_reason = PPTP_STOP_NONE; assert(conn && conn->call); assert(buffer); assert(ntoh32(header->magic) == PPTP_MAGIC); assert(ntoh16(header->length) == size); assert(ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL); if (size < PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))) { log("Invalid packet received [type: %d; length: %d].", (int) ntoh16(header->ctrl_type), (int) size); return 0; } switch (ntoh16(header->ctrl_type)) { /* ----------- STANDARD Start-Session MESSAGES ------------ */ case PPTP_START_CTRL_CONN_RQST: { struct pptp_start_ctrl_conn *packet = (struct pptp_start_ctrl_conn *) buffer; struct pptp_start_ctrl_conn reply = { PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY), hton16(PPTP_VERSION), 0, 0, hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP), hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION), PPTP_HOSTNAME, PPTP_VENDOR }; int idx, rc; log("Received Start Control Connection Request"); /* fix this packet, if necessary */ idx = get_quirk_index(); if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) { if ((rc = pptp_fixups[idx].start_ctrl_conn(&reply))) warn("calling the start_ctrl_conn hook failed (%d)", rc); } if (conn->conn_state == CONN_IDLE) { if (ntoh16(packet->version) < PPTP_VERSION) { /* Can't support this (earlier) PPTP_VERSION */ reply.version = packet->version; /* protocol version not supported */ reply.result_code = hton8(5); if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) pptp_reset_timer(); /* give sender a chance for a retry */ } else { /* same or greater version */ if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) { conn->conn_state = CONN_ESTABLISHED; log("server connection ESTABLISHED."); pptp_reset_timer(); } } } break; } case PPTP_START_CTRL_CONN_RPLY: { struct pptp_start_ctrl_conn *packet = (struct pptp_start_ctrl_conn *) buffer; log("Received Start Control Connection Reply"); if (conn->conn_state == CONN_WAIT_CTL_REPLY) { /* XXX handle collision XXX [see rfc] */ if (ntoh16(packet->version) != PPTP_VERSION) { if (conn->callback != NULL) conn->callback(conn, CONN_OPEN_FAIL); close_reason = PPTP_STOP_PROTOCOL; goto pptp_conn_close; } if (ntoh8(packet->result_code) != 1 && /* J'ai change le if () afin que la connection ne se ferme * pas pour un "rien" :p adel@cybercable.fr - * * Don't close the connection if the result code is zero * (feature found in certain ADSL modems) */ ntoh8(packet->result_code) != 0) { log("Negative reply received to our Start Control " "Connection Request"); ctrlp_error(packet->result_code, packet->error_code, -1, pptp_start_ctrl_conn_rply, MAX_START_CTRL_CONN_REPLY); if (conn->callback != NULL) conn->callback(conn, CONN_OPEN_FAIL); close_reason = PPTP_STOP_PROTOCOL; goto pptp_conn_close; } conn->conn_state = CONN_ESTABLISHED; /* log session properties */ conn->version = ntoh16(packet->version); conn->firmware_rev = ntoh16(packet->firmware_rev); memcpy(conn->hostname, packet->hostname, sizeof(conn->hostname)); memcpy(conn->vendor, packet->vendor, sizeof(conn->vendor)); pptp_reset_timer(); /* 60 seconds until keep-alive */ log("Client connection established."); if (conn->callback != NULL) conn->callback(conn, CONN_OPEN_DONE); } /* else goto pptp_conn_close; */ break; } /* ----------- STANDARD Stop-Session MESSAGES ------------ */ case PPTP_STOP_CTRL_CONN_RQST: { /* conn_state should be CONN_ESTABLISHED, but it could be * something else */ struct pptp_stop_ctrl_conn reply = { PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY), hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0 }; log("Received Stop Control Connection Request."); if (conn->conn_state == CONN_IDLE) break; if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) { if (conn->callback != NULL) conn->callback(conn, CONN_CLOSE_RQST); conn->conn_state = CONN_IDLE; return -1; } break; } case PPTP_STOP_CTRL_CONN_RPLY: { log("Received Stop Control Connection Reply."); /* conn_state should be CONN_WAIT_STOP_REPLY, but it * could be something else */ if (conn->conn_state == CONN_IDLE) break; conn->conn_state = CONN_IDLE; return -1; } /* ----------- STANDARD Echo/Keepalive MESSAGES ------------ */ case PPTP_ECHO_RPLY: { struct pptp_echo_rply *packet = (struct pptp_echo_rply *) buffer; logecho( PPTP_ECHO_RPLY); if ((conn->ka_state == KA_OUTSTANDING) && (ntoh32(packet->identifier) == conn->ka_id)) { conn->ka_id++; conn->ka_state = KA_NONE; pptp_reset_timer(); } break; } case PPTP_ECHO_RQST: { struct pptp_echo_rqst *packet = (struct pptp_echo_rqst *) buffer; struct pptp_echo_rply reply = { PPTP_HEADER_CTRL(PPTP_ECHO_RPLY), packet->identifier, /* skip hton32(ntoh32(id)) */ hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0 }; logecho( PPTP_ECHO_RQST); if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) pptp_reset_timer(); break; } /* ----------- OUTGOING CALL MESSAGES ------------ */ case PPTP_OUT_CALL_RQST: { struct pptp_out_call_rqst *packet = (struct pptp_out_call_rqst *)buffer; struct pptp_out_call_rply reply = { PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY), 0 /* callid */, packet->call_id, 1, PPTP_GENERAL_ERROR_NONE, 0, hton32(PPTP_CONNECT_SPEED), hton16(PPTP_WINDOW), hton16(PPTP_DELAY), 0 }; log("Received Outgoing Call Request."); /* XXX PAC: eventually this should make an outgoing call. XXX */ reply.result_code = hton8(7); /* outgoing calls verboten */ pptp_send_ctrl_packet(conn, &reply, sizeof(reply)); break; } case PPTP_OUT_CALL_RPLY: { struct pptp_out_call_rply *packet = (struct pptp_out_call_rply *)buffer; PPTP_CALL * call; u_int16_t callid = ntoh16(packet->call_id_peer); log("Received Outgoing Call Reply."); if (!vector_search(conn->call, (int) callid, &call)) { log("PPTP_OUT_CALL_RPLY received for non-existant call: " "peer call ID (us) %d call ID (them) %d.", callid, ntoh16(packet->call_id)); break; } if (call->call_type != PPTP_CALL_PNS) { log("Ack! How did this call_type get here?"); /* XXX? */ break; } if (call->state.pns != PNS_WAIT_REPLY) { warn("Unexpected(?) Outgoing Call Reply will be ignored."); break; } /* check for errors */ if (packet->result_code != 1) { /* An error. Log it verbosely. */ log("Our outgoing call request [callid %d] has not been " "accepted.", (int) callid); ctrlp_error(packet->result_code, packet->error_code, packet->cause_code, pptp_out_call_reply_result, MAX_OUT_CALL_REPLY_RESULT); call->state.pns = PNS_IDLE; if (call->callback != NULL) call->callback(conn, call, CALL_OPEN_FAIL); pptp_call_destroy(conn, call); } else { /* connection established */ call->state.pns = PNS_ESTABLISHED; call->peer_call_id = ntoh16(packet->call_id); call->speed = ntoh32(packet->speed); pptp_reset_timer(); /* call pptp_set_link. unless the user specified a quirk and this quirk has a set_link hook, this is a noop */ pptp_set_link(conn, call->peer_call_id); if (call->callback != NULL) call->callback(conn, call, CALL_OPEN_DONE); log("Outgoing call established (call ID %u, peer's " "call ID %u).\n", call->call_id, call->peer_call_id); } break; } /* ----------- INCOMING CALL MESSAGES ------------ */ /* XXX write me XXX */ /* ----------- CALL CONTROL MESSAGES ------------ */ case PPTP_CALL_CLEAR_RQST: { struct pptp_call_clear_rqst *packet = (struct pptp_call_clear_rqst *)buffer; struct pptp_call_clear_ntfy reply = { PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_NTFY), packet->call_id, 1, PPTP_GENERAL_ERROR_NONE, 0, 0, {0} }; log("Received Call Clear Request."); if (vector_contains(conn->call, ntoh16(packet->call_id))) { PPTP_CALL * call; vector_search(conn->call, ntoh16(packet->call_id), &call); if (call->callback != NULL) call->callback(conn, call, CALL_CLOSE_RQST); if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) { pptp_call_destroy(conn, call); log("Call closed (RQST) (call id %d)", (int) call->call_id); } } break; } case PPTP_CALL_CLEAR_NTFY: { struct pptp_call_clear_ntfy *packet = (struct pptp_call_clear_ntfy *)buffer; int i; u_int16_t our_call_id; u_int16_t peer_call_id = ntoh16(packet->call_id); log("Call disconnect notification received (call id %d)", (int) peer_call_id); /* See if we can map the peer's call id to our own */ for (i = 0; i < vector_size(conn->call); i++) { PPTP_CALL * call = vector_get_Nth(conn->call, i); if (call->peer_call_id == peer_call_id) { our_call_id = call->call_id; if (vector_contains(conn->call, our_call_id)) { ctrlp_error(packet->result_code, packet->error_code, packet->cause_code, pptp_call_disc_ntfy, MAX_CALL_DISC_NTFY); vector_search(conn->call, our_call_id, &call); pptp_call_destroy(conn, call); } break; } } /* XXX we could log call stats here XXX */ /* XXX not all servers send this XXX */ break; } case PPTP_SET_LINK_INFO: { /* I HAVE NO CLUE WHAT TO DO IF send_accm IS NOT 0! */ /* this is really dealt with in the HDLC deencapsulation, anyway. */ struct pptp_set_link_info *packet = (struct pptp_set_link_info *)buffer; /* log it. */ log("PPTP_SET_LINK_INFO received from peer_callid %u", (unsigned int) ntoh16(packet->call_id_peer)); log(" send_accm is %08lX, recv_accm is %08lX", (unsigned long) ntoh32(packet->send_accm), (unsigned long) ntoh32(packet->recv_accm)); if (!(ntoh32(packet->send_accm) == 0 && ntoh32(packet->recv_accm) == 0)) warn("Non-zero Async Control Character Maps are not supported!"); break; } default: log("Unrecognized Packet %d received.", (int) ntoh16(((struct pptp_header *)buffer)->ctrl_type)); /* goto pptp_conn_close; */ break; } return 0; pptp_conn_close: warn("pptp_conn_close(%d)", (int) close_reason); pptp_conn_close(conn, close_reason); return 0; } /*** pptp_set_link **************************************************************/ void pptp_set_link(PPTP_CONN* conn, int peer_call_id) { int idx, rc; /* if we need to send a set_link packet because of buggy hardware or pptp server, do it now */ if ((idx = get_quirk_index()) != -1 && pptp_fixups[idx].set_link_hook) { struct pptp_set_link_info packet; if ((rc = pptp_fixups[idx].set_link_hook(&packet, peer_call_id))) warn("calling the set_link hook failed (%d)", rc); if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) { pptp_reset_timer(); } } } /*** Get info from call structure *********************************************/ /* NOTE: The peer_call_id is undefined until we get a server response. */ void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call, u_int16_t * call_id, u_int16_t * peer_call_id) { assert(conn != NULL); assert(call != NULL); *call_id = call->call_id; *peer_call_id = call->peer_call_id; } /*** pptp_call_closure_put ****************************************************/ void pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl) { assert(conn != NULL); assert(call != NULL); call->closure = cl; } /*** pptp_call_closure_get ****************************************************/ void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call) { assert(conn != NULL); assert(call != NULL); return call->closure; } /*** pptp_conn_closure_put ****************************************************/ void pptp_conn_closure_put(PPTP_CONN * conn, void *cl) { assert(conn != NULL); conn->closure = cl; } /*** pptp_conn_closure_get ****************************************************/ void * pptp_conn_closure_get(PPTP_CONN * conn) { assert(conn != NULL); return conn->closure; } /*** Reset keep-alive timer ***************************************************/ static void pptp_reset_timer(void) { const struct itimerval tv = { { 0, 0 }, /* stop on time-out */ { idle_wait, 0 } }; if (idle_wait) setitimer(ITIMER_REAL, &tv, NULL); } /*** Handle keep-alive timer **************************************************/ static void pptp_handle_timer(void) { int i; /* "Keep Alives and Timers, 1": check connection state */ if (global.conn->conn_state != CONN_ESTABLISHED) { if (global.conn->conn_state == CONN_WAIT_STOP_REPLY) { /* hard close. */ pptp_conn_destroy(global.conn); return; } /* soft close */ pptp_conn_close(global.conn, PPTP_STOP_NONE); } /* "Keep Alives and Timers, 2": check echo status */ if (global.conn->ka_state == KA_OUTSTANDING) { /* no response to keep-alive */ log ("closing control connection due to missing echo reply"); pptp_conn_close(global.conn, PPTP_STOP_NONE); } else { /* ka_state == NONE */ /* send keep-alive */ struct pptp_echo_rqst rqst = { PPTP_HEADER_CTRL(PPTP_ECHO_RQST), hton32(global.conn->ka_id) }; if (pptp_send_ctrl_packet(global.conn, &rqst, sizeof(rqst))) { global.conn->ka_state = KA_OUTSTANDING; } } /* check incoming/outgoing call states for !IDLE && !ESTABLISHED */ for (i = 0; i < vector_size(global.conn->call); i++) { PPTP_CALL * call = vector_get_Nth(global.conn->call, i); if (call->call_type == PPTP_CALL_PNS) { if (call->state.pns == PNS_WAIT_REPLY) { /* send close request */ pptp_call_close(global.conn, call); assert(call->state.pns == PNS_WAIT_DISCONNECT); } else if (call->state.pns == PNS_WAIT_DISCONNECT) { /* hard-close the call */ pptp_call_destroy(global.conn, call); } } else if (call->call_type == PPTP_CALL_PAC) { if (call->state.pac == PAC_WAIT_REPLY) { /* XXX FIXME -- drop the PAC connection XXX */ } else if (call->state.pac == PAC_WAIT_CS_ANS) { /* XXX FIXME -- drop the PAC connection XXX */ } } } pptp_reset_timer(); } pptp-1.8.0/test.c0000644000175000017500000001252712231702206012610 0ustar jamesjames/* Packet reordering test implementation, intended to cause packets to be reordered for testing pptpd and other servers. Avoids the use of pqueue.c so that it can be tested independently. */ #include #include #include #include "util.h" #include "test.h" /* whether we are asked to test ordering, obtained from command line */ extern int test_type; /* rate at which to do test ordering changes */ extern int test_rate; /* trigger cycle */ static int test_ordering_cycle = 0; /* phase of reordering */ static int test_ordering_phase = 0; /* swap a packet every now and then */ static ssize_t write_reordered_swap(int fd, const void *buf, size_t count) { static void *pocket_buf = NULL; static int pocket_count = 0; int stat; switch (test_ordering_phase) { case 0: /* between triggers, send as normal */ test_ordering_cycle++; if (test_ordering_cycle == test_rate) test_ordering_phase++; return write(fd, buf, count); case 1: /* triggered, swap a packet */ test_ordering_cycle++; if (test_ordering_cycle == (test_rate+1)) { /* pocket the packet */ pocket_count = count; pocket_buf = malloc(count); memcpy(pocket_buf, buf, count); log("test order swap, packet buffered"); /* lie about the result */ return count; } else { /* after this, reset to normal */ test_ordering_cycle = 0; test_ordering_phase = 0; /* send the new packet first */ stat = write(fd, buf, count); if ((size_t)stat != count) return stat; /* then send the old packet next */ stat = write(fd, pocket_buf, pocket_count); free(pocket_buf); log("test order swap, packets sent"); return count; } default: return write(fd, buf, count); } } /* hold ten packets and send the eleventh, then the ten in order */ static ssize_t write_reordered_retransmit(int fd, const void *buf, size_t count) { int test_length = 10; static void *pocket_buf[10]; static int pocket_count[10]; int stat, n; switch (test_ordering_phase) { case 0: /* between triggers, send as normal */ test_ordering_cycle++; if (test_ordering_cycle == test_rate) test_ordering_phase++; return write(fd, buf, count); case 1: /* triggered, buffer the packets */ test_ordering_cycle++; if (test_ordering_cycle == (test_rate+test_length)) { test_ordering_phase = 2; } /* pocket the packet */ n = test_ordering_cycle - test_rate - 1; pocket_count[n] = count; pocket_buf[n] = malloc(count); memcpy(pocket_buf[n], buf, count); log("test order retransmit, packet buffered"); /* lie about the result */ return count; case 2: /* after this, reset to normal */ test_ordering_cycle = 0; test_ordering_phase = 0; /* send the new packet first */ stat = write(fd, buf, count); if ((size_t)stat != count) return stat; /* send the buffered packets in normal order */ for (n=0; n0; n--) { stat = write(fd, pocket_buf[n], pocket_count[n]); /* ignores failures */ free(pocket_buf[n]); } log("test order reverse, packets sent"); return count; default: return write(fd, buf, count); } } /* dispatcher for write reordering tests */ static ssize_t write_reordered(int fd, const void *buf, size_t count) { switch (test_type) { case 1: /* swap a packet every now and then */ return write_reordered_swap(fd, buf, count); case 2: /* hold ten packets and send the eleventh, then the ten in order */ return write_reordered_retransmit(fd, buf, count); case 3: /* hold ten packets and send them in reverse order */ return write_reordered_reverse(fd, buf, count); default: return write(fd, buf, count); } } struct test_redirections *test_redirections(void) { static struct test_redirections *my = NULL; if (my == NULL) my = malloc(sizeof(struct test_redirections)); my->write = write; if (test_type) my->write = write_reordered; return my; } pptp-1.8.0/pptp_quirks.h0000644000175000017500000000330012231702206014204 0ustar jamesjames/* pptp_quirks.h ...... various options to fix quirks found in buggy adsl modems * mulix * * $Id: pptp_quirks.h,v 1.2 2011/12/19 07:15:03 quozl Exp $ */ #ifndef INC_PPTP_QUIRKS_H #define INC_PPTP_QUIRKS_H /* isp defs - correspond to slots in the fixups table */ #define BEZEQ_ISRAEL "BEZEQ_ISRAEL" /* vendor defs */ #define ORCKIT 1 #define ALCATEL 2 /* device defs */ #define ORCKIT_ATUR2 1 #define ORCKIT_ATUR3 2 #include "pptp_msg.h" #include "pptp_ctrl.h" struct pptp_fixup { const char* isp; /* which isp? e.g. Bezeq in Israel */ int vendor; /* which vendor? e.g. Orckit */ int device; /* which device? e.g. Orckit Atur3 */ /* use this hook to build your own out call request packet */ int (*out_call_rqst_hook)(struct pptp_out_call_rqst* packet); /* use this hook to build your own start control connection packet */ /* note that this hook is called from two different places, depending on whether this is a request or reply */ int (*start_ctrl_conn)(struct pptp_start_ctrl_conn* packet); /* use this hook if you need to send a 'set_link' packet once the connection is established */ int (*set_link_hook)(struct pptp_set_link_info* packet, int peer_call_id); }; extern struct pptp_fixup pptp_fixups[]; /* find the index for this isp in the quirks table */ /* return the index on success, -1 if not found */ int find_quirk(const char* isp_name); /* set the global quirk index. return 0 on success, non 0 otherwise */ int set_quirk_index(int index); /* get the global quirk index. return the index on success, -1 if no quirk is defined */ int get_quirk_index(void); #endif /* INC_PPTP_QUIRKS_H */ pptp-1.8.0/ppp_fcs.h0000644000175000017500000000056612231702206013270 0ustar jamesjames/* ppp_fcs.h ... header file for PPP-HDLC FCS * C. Scott Ananian * * $Id: ppp_fcs.h,v 1.2 2008/02/19 05:05:03 quozl Exp $ */ #include "pptp_compat.h" #define PPPINITFCS16 0xffff /* Initial FCS value */ #define PPPGOODFCS16 0xf0b8 /* Good final FCS value */ u_int16_t pppfcs16(u_int16_t fcs, void *cp, int len); pptp-1.8.0/COPYING0000644000175000017500000004325412231702206012521 0ustar jamesjames GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. pptp-1.8.0/AUTHORS0000644000175000017500000000202412231702206012524 0ustar jamesjamesPrimary author of this package (when it was called pptp-linux): C. Scott Ananian Patches and bug-fixes by: Christoph Lameter Gordon Chaffee mulix James Cameron Rein Klazes Thomas Quinot Rhialto Scott Venier Jeff Wiedemeier Yura Zotov Chris Wilson Ed Marcotte Jan Pieter Ed Meaney Yury Tarasievich Paul Howarth Peter Surda Nelson Ferraz Michael Adda Ilya Voronin Charles Shen Jan Just Keijser David Lamparter Package renamed from pptp-linux to pptp after version 1.5.0. $Id: AUTHORS,v 1.21 2011/02/22 02:25:24 quozl Exp $ pptp-1.8.0/inststr.c0000644000175000017500000000524012231702206013331 0ustar jamesjames/* inststr.c ... stolen from bdupdate.c, which stole it from perl 4. * Theft by C. Scott Ananian * Modified similarly to perl 5.8.3's alignment-checking code 8 by Paul Howarth * * $Id: inststr.c,v 1.3 2004/06/08 23:40:14 quozl Exp $ */ #include #define PTRSIZE sizeof(void *) typedef unsigned long UL; void inststr(int argc, char **argv, char **environ, char *src) { if (strlen(src) <= strlen(argv[0])) { char *ptr; for (ptr = argv[0]; *ptr; *(ptr++) = '\0'); strcpy(argv[0], src); } else { /* Stolen from the source to perl 4.036 (assigning to $0) */ /* Modified to allow for aligned array members, assuming */ /* no system has something bizarre like the argv[] */ /* interleaved with some other data. Also allow for argv */ /* array having higher numbered elements lower in memory */ /* than lower numbered elements. */ char *ptr, *ptr2; int count; UL mask = ~(UL)(PTRSIZE == 4 ? 3 : PTRSIZE == 8 ? 7 : PTRSIZE == 16 ? 15 : 0); int aligned = (mask < ~(UL)0) && (((UL)(argv[0]) & mask) == (UL)(argv[0])); ptr = argv[0] + strlen(argv[0]); if (argv[argc - 1] >= argv[1]) { /* argv pointers in ascending memory order */ for (count = 1; count < argc; count++) { if (argv[count] == ptr + 1 || (aligned && argv[count] > ptr && argv[count] <= (char *)((UL)(ptr + PTRSIZE) & mask)) ) { ptr = argv[count] + strlen(argv[count]); } } } else { /* sometimes the argv pointers go down in memory rather than up */ for (count = argc - 1; count > 0; count--) { if (argv[count] == ptr + 1 || (aligned && argv[count] > ptr && argv[count] <= (char *)((UL)(ptr + PTRSIZE) & mask)) ) { ptr = argv[count] + strlen(argv[count]); } } } for (count = 0; environ[count]; count++) { if (environ[count] == ptr + 1 || (aligned && environ[count] > ptr && environ[count] <= (char *)((UL)(ptr + PTRSIZE) & mask)) ) { ptr = environ[count] + strlen(environ[count]); } } count = 0; for (ptr2 = argv[0]; ptr2 <= ptr; ptr2++) { *ptr2 = '\0'; count++; } strncpy(argv[0], src, count); } } pptp-1.8.0/dirutil.c0000644000175000017500000000357112231702206013304 0ustar jamesjames/* dirutil.c ... directory utilities. * C. Scott Ananian * * $Id: dirutil.c,v 1.2 2003/06/17 17:25:47 reink Exp $ */ #include #include #include #include #include #include "dirutil.h" /* Returned malloc'ed string representing basename */ char *basenamex(char *pathname) { char *dup = strdup(pathname); char *ptr = strrchr(stripslash(dup), '/'); if (ptr == NULL) return dup; ptr = strdup(ptr+1); free(dup); return ptr; } /* Return malloc'ed string representing directory name (no trailing slash) */ char *dirname(char *pathname) { char *dup = strdup(pathname); char *ptr = strrchr(stripslash(dup), '/'); if (ptr == NULL) { free(dup); return strdup("."); } if (ptr == dup && dup[0] == '/') ptr++; *ptr = '\0'; return dup; } /* In-place modify a string to remove trailing slashes. Returns arg. * stripslash("/") returns "/"; */ char *stripslash(char *pathname) { int len = strlen(pathname); while (len > 1 && pathname[len - 1] == '/') pathname[--len] = '\0'; return pathname; } /* ensure dirname exists, creating it if necessary. */ int make_valid_path(char *dir, mode_t mode) { struct stat st; char *tmp = NULL, *path = stripslash(strdup(dir)); int retval; if (stat(path, &st) == 0) { /* file exists */ if (S_ISDIR(st.st_mode)) { retval = 1; goto end; } else { retval = 0; goto end; } /* not a directory. Oops. */ } /* Directory doesn't exist. Let's make it. */ /* Make parent first. */ if (!make_valid_path(tmp = dirname(path), mode)) { retval = 0; goto end; } /* Now make this 'un. */ if (mkdir(path, mode) < 0) { retval = 0; goto end; } /* Success. */ retval = 1; end: if (tmp != NULL) free(tmp); if (path != NULL) free(path); return retval; } pptp-1.8.0/pptp_compat.c0000644000175000017500000000331012231702206014145 0ustar jamesjames/* pptp_compat.c ... Compatibility functions * */ #include #include #include #include #include #include #if defined (__SVR4) && defined (__sun) /* Solaris */ #include #endif #include #include "pptp_compat.h" #include #include "util.h" #if defined (__SVR4) && defined (__sun) /* Solaris */ /* * daemon implementation from uClibc */ int daemon(int nochdir, int noclose) { int fd; switch (fork()) { case -1: return (-1); case 0: break; default: _exit(0); } if (setsid() == -1) return (-1); if (!nochdir) chdir("/"); if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if (fd > 2) close (fd); } return (0); } /* * openpty implementation based on pts(7D) example */ int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize * winp) { int fdm,fds; char * slavename; /* open master */ if ( (fdm = open("/dev/ptmx", O_RDWR)) == -1 ) return -1; /* grant access to the slave pseudo-terminal device */ if ( grantpt(fdm) == -1 ) return -1; /* unlock a pseudo-terminal master/slave pair */ if ( unlockpt(fdm) == -1 ) return -1; /* get name of the slave pseudo-terminal device */ if ( (slavename = ptsname(fdm)) == NULL ) return -1; if ( (fds = open(slavename, O_RDWR)) == -1 ) { free(slavename); return -1; } ioctl(fds, I_PUSH, "ptem"); /* push ptem */ ioctl(fds, I_PUSH, "ldterm"); /* push ldterm*/ if ( name != NULL ) strcpy(name,slavename); *amaster = fdm; *aslave = fds; free(slavename); return 0; } #endif /* Solaris */ pptp-1.8.0/routing.c0000644000175000017500000001213612231702206013314 0ustar jamesjames/* routing.c, manipulating routing table for PPTP Client Copyright (C) 2006 James Cameron This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include "routing.h" #include "config.h" #if defined (__SVR4) && defined (__sun) /* Solaris */ #include #include #include #include #include #include "util.h" /* PF_ROUTE socket*/ int rts; /* Destination and gateway addresses */ struct sockaddr_in rdst, rgw; /* Request sequence */ int rseq; int dorouting; #else /* Solaris */ /* route to the server */ char *route; #endif /* Solaris */ /* Design discussion. The primary task of this module is to add a host route to the PPTP server so that the kernel continues to deliver PPTP control and data connection packets to the server despite the new PPP interface that is created. The flag --nohostroute is to disable this. A secondary task may be to implement all-to-tunnel routing if the appropriate flag is specified on the command line. The flag --route-all is to implement this (not yet implemented). Caveat. It is not possible from the "ip route" command to determine if a host route already exists, so it isn't practical to put the routing table back exactly as it was. We have a choice of either leaving our route lying around, or destroying a route that the user had pre-arranged. Both are unfortunate. The flag --remove-host-route is to remove the route regardless (not yet implemented). */ void routing_init(char *ip) { #if defined (__SVR4) && defined (__sun) /* Solaris */ rdst.sin_family = AF_INET; if ( ! inet_pton(AF_INET, ip, &rdst.sin_addr) ) { log("Cannot convert address: %s", strerror(errno)); return; } if ( (rts = socket(PF_ROUTE, SOCK_RAW, AF_INET )) < 0 ) { log("Cannot open routing socket: %s", strerror(errno)); return; } struct rt_msg rtm = { .hdr.rtm_msglen = sizeof(struct rt_msg), .hdr.rtm_version = RTM_VERSION, .hdr.rtm_type = RTM_GET, .hdr.rtm_addrs = RTA_DST, .hdr.rtm_pid = getpid(), .hdr.rtm_seq = ++rseq, .addrs[RTAX_DST] = rdst }; if ( write(rts, &rtm, rtm.hdr.rtm_msglen) != rtm.hdr.rtm_msglen ) { log("Error writing to routing socket: %s", strerror(errno)); close(rts); return; } while ( read(rts, &rtm, sizeof(struct rt_msg)) > 0 ) if ( rtm.hdr.rtm_pid == getpid() && rtm.hdr.rtm_seq == rseq) { /* Check if host route already present */ if ( ( rtm.hdr.rtm_flags & RTF_HOST ) != RTF_HOST ) { rgw = rtm.addrs[RTAX_GATEWAY]; dorouting = 1; } break; } #else /* Solaris */ char buf[256]; FILE *p; snprintf(buf, 255, "%s route get %s", IP_BINARY, ip); p = popen(buf, "r"); fgets(buf, 255, p); /* TODO: check for failure of fgets */ route = strdup(buf); pclose(p); /* TODO: check for failure of command */ #endif /* Solaris */ } void routing_start(void) { #if defined (__SVR4) && defined (__sun) /* Solaris */ if ( ! dorouting ) return; struct rt_msg rtm = { .hdr.rtm_msglen = sizeof(struct rt_msg), .hdr.rtm_version = RTM_VERSION, .hdr.rtm_type = RTM_ADD, .hdr.rtm_flags = RTF_HOST | RTF_GATEWAY | RTF_STATIC, .hdr.rtm_addrs = RTA_DST | RTA_GATEWAY, .hdr.rtm_pid = getpid(), .hdr.rtm_seq = ++rseq, .addrs[RTAX_DST] = rdst, .addrs[RTAX_GATEWAY] = rgw }; if ( write(rts, &rtm, rtm.hdr.rtm_msglen) != rtm.hdr.rtm_msglen ) { log("Error adding route: %s", strerror(errno)); } #else /* Solaris */ char buf[256]; FILE *p; snprintf(buf, 255, "%s route replace %s", IP_BINARY, route); p = popen(buf, "r"); pclose(p); #endif /* Solaris */ } void routing_end(void) { #if defined (__SVR4) && defined (__sun) /* Solaris */ if ( ! dorouting) return; struct rt_msg rtm = { .hdr.rtm_msglen = sizeof(struct rt_msg), .hdr.rtm_version = RTM_VERSION, .hdr.rtm_type = RTM_DELETE, .hdr.rtm_flags = RTF_HOST | RTF_GATEWAY | RTF_STATIC, .hdr.rtm_addrs = RTA_DST | RTA_GATEWAY, .hdr.rtm_pid = getpid(), .hdr.rtm_seq = ++rseq, .addrs[RTAX_DST] = rdst, .addrs[RTAX_GATEWAY] = rgw }; if ( write(rts, &rtm, rtm.hdr.rtm_msglen) != rtm.hdr.rtm_msglen ) { log("Error deleting route: %s", strerror(errno)); } #else /* Solaris */ char buf[256]; FILE *p; snprintf(buf, 255, "%s route delete %s", IP_BINARY, route); p = popen(buf, "r"); pclose(p); #endif /* Solaris */ } pptp-1.8.0/orckit_quirks.c0000644000175000017500000000416512231702206014521 0ustar jamesjames/* orckit_quirks.c ...... fix quirks in orckit adsl modems * mulix * * $Id: orckit_quirks.c,v 1.4 2011/12/19 07:13:30 quozl Exp $ */ #include #include #include #include "pptp_msg.h" #include "pptp_options.h" #include "pptp_ctrl.h" #include "util.h" /* return 0 on success, non zero otherwise */ int orckit_atur3_build_hook(struct pptp_out_call_rqst* packet) { unsigned int name_length = 10; struct pptp_out_call_rqst fixed_packet = { PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST), 0, /* hton16(call->callid) */ 0, /* hton16(call->sernum) */ hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX), hton32(PPTP_BEARER_DIGITAL), hton32(PPTP_FRAME_ANY), hton16(PPTP_WINDOW), 0, hton16(name_length), 0, {'R','E','L','A','Y','_','P','P','P','1',0}, {0} }; if (!packet) return -1; memcpy(packet, &fixed_packet, sizeof(*packet)); return 0; } /* return 0 on success, non zero otherwise */ int orckit_atur3_set_link_hook(struct pptp_set_link_info* packet, int peer_call_id) { struct pptp_set_link_info fixed_packet = { PPTP_HEADER_CTRL(PPTP_SET_LINK_INFO), hton16(peer_call_id), 0, 0xffffffff, 0xffffffff}; if (!packet) return -1; memcpy(packet, &fixed_packet, sizeof(*packet)); return 0; } /* return 0 on success, non 0 otherwise */ int orckit_atur3_start_ctrl_conn_hook(struct pptp_start_ctrl_conn* packet) { struct pptp_start_ctrl_conn fixed_packet = { {0, 0, 0, 0 , 0}, /* we'll set the header later */ hton16(PPTP_VERSION), 0, 0, hton32(PPTP_FRAME_ASYNC), hton32(PPTP_BEARER_ANALOG), hton16(0) /* max channels */, hton16(0x6021), {'R','E','L','A','Y','_','P','P','P','1',0}, /* hostname */ {'M','S',' ','W','i','n',' ','N','T',0} /* vendor */ }; if (!packet) return -1; /* grab the header from the original packet, since we dont know if this is a request or a reply */ memcpy(&fixed_packet.header, &packet->header, sizeof(struct pptp_header)); /* and now overwrite the full packet, effectively preserving the header */ memcpy(packet, &fixed_packet, sizeof(*packet)); return 0; } pptp-1.8.0/version.h0000644000175000017500000000044212231702206013314 0ustar jamesjames/* version.h ..... keep track of package version number. * C. Scott Ananian * * $Id: version.h,v 1.1 2000/12/23 08:19:51 scott Exp $ */ #ifndef INC_VERSION_H #define INC_VERSION_H extern const char * version; #endif /* INC_VERSION_H */ pptp-1.8.0/pptp_quirks.c0000644000175000017500000000210112231702206014175 0ustar jamesjames/* pptp_quirks.c ...... various options to fix quirks found in buggy adsl modems * mulix * * $Id: pptp_quirks.c,v 1.3 2011/12/19 07:15:03 quozl Exp $ */ #include #include "orckit_quirks.h" #include "pptp_quirks.h" static int quirk_index = -1; struct pptp_fixup pptp_fixups[] = { {BEZEQ_ISRAEL, ORCKIT, ORCKIT_ATUR3, orckit_atur3_build_hook, orckit_atur3_start_ctrl_conn_hook, orckit_atur3_set_link_hook} }; static int fixups_sz = sizeof(pptp_fixups)/sizeof(pptp_fixups[0]); /* return 0 on success, non 0 otherwise */ int set_quirk_index(int index) { if (index >= 0 && index < fixups_sz) { quirk_index = index; return 0; } return -1; } int get_quirk_index(void) { return quirk_index; } /* return the index for this isp in the quirks table, -1 if not found */ int find_quirk(const char* isp_name) { int i = 0; if (isp_name) { while (i < fixups_sz && pptp_fixups[i].isp) { if (!strcmp(pptp_fixups[i].isp, isp_name)) { return i; } ++i; } } return -1; } pptp-1.8.0/pptp_compat.h0000644000175000017500000000066012231702206014157 0ustar jamesjames/* pptp_compat.h ... Compatibility functions * */ #if defined (__SVR4) && defined (__sun) /* Solaris */ #include #define u_int8_t uint8_t #define u_int16_t uint16_t #define u_int32_t uint32_t #ifndef INADDR_NONE #define INADDR_NONE 0xffffffffU #endif int daemon(int nochdir, int noclose); int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize * winp); #endif /* Solaris */ pptp-1.8.0/orckit_quirks.h0000644000175000017500000000131612231702206014521 0ustar jamesjames/* orckit_quirks.h ...... fix quirks in orckit adsl modems * mulix * * $Id: orckit_quirks.h,v 1.2 2001/11/23 03:42:51 quozl Exp $ */ #ifndef INC_ORCKIT_QUIRKS_H_ #define INC_ORCKIT_QUIRKS_H_ #include "pptp_options.h" #include "pptp_ctrl.h" #include "pptp_msg.h" /* return 0 on success, non zero otherwise */ int orckit_atur3_build_hook(struct pptp_out_call_rqst* packt); /* return 0 on success, non zero otherwise */ int orckit_atur3_set_link_hook(struct pptp_set_link_info* packet, int peer_call_id); /* return 0 on success, non zero otherwise */ int orckit_atur3_start_ctrl_conn_hook(struct pptp_start_ctrl_conn* packet); #endif /* INC_ORCKIT_QUIRKS_H_ */ pptp-1.8.0/Documentation/0000755000175000017500000000000012231702206014267 5ustar jamesjamespptp-1.8.0/Documentation/PORTING0000644000175000017500000000503712231702206015341 0ustar jamesjamespptp uses very few linux-specific features, and should be easily portable to most Unix systems. Two things to watch: 1) The code in pty.[ch] to find a free pty/tty pair. This was conceptually borrowed from the xterm sources, which need to do more or less the same thing. *But* the xterm sources had a heck of a lot more system-specific #defines to cover all the eccentric unix variants out there. If you are porting this code to a non-unix system, I would recommend downloading the xterm sources to find out how pty.[ch] should look for your system. Xterm is in the standard X distribution, or you can download SRRMs from ftp.redhat.com. Configure the xterm sources for your machine, and then preprocess main.c with these configuration options. E.g. I did: [cananian@cananian xterm-sb_right-ansi-3d]# make main.o rm -f main.o gcc -c -O2 -fno-strength-reduce -m486 -I/usr/X11R6/include -Dlinux -D__i386__ -D_POSIX_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE -DX_LOCALE -DFUNCPROTO=15 -DNARROWPROTO -DUTMP -DUSE_TTY_GROUP -DOSMAJORVERSION=2 -DOSMINORVERSION=0 main.c So the appropriate preprocessing command would be: [cananian@cananian xterm-sb_right-ansi-3d]# gcc -E -O2 -fno-strength-reduce -m486 -I/usr/X11R6/include -Dlinux -D__i386__ -D_POSIX_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE -DX_LOCALE -DFUNCPROTO=15 -DNARROWPROTO -DUTMP -DUSE_TTY_GROUP -DOSMAJORVERSION=2 -DOSMINORVERSION=0 main.c > main.CPP Grok through the sources to figure out how the ptys are allocated on your machine. I suspect many people will want to look carefully at the function pty_search(), but there are architectures that have other, built-in, functions for doing the same thing. Add the code to pty.[ch] with the proper #ifdefs, mail a patch back to me at and you're good to go! 2) The pptp_gre_copy function opens an IP protocol socket with: s = socket(AF_INET, SOCK_RAW, PPTP_PROTO); where PPTP_PROTO is #define'd in the code to be 47. I *think* that this should work across Unix variants, but if your system has a different method for opening a non-TCP, raw-IP-protocol-47 socket, then you'll have to make some changes here, and perhaps in decaps_gre and encaps_gre as well. OK. Those are the only two potential non-portabilities I can think of. I should really be using automake/autoconf, of course, as well. --Scott 15Dec1997 -------------------------------------------------------------------- C. Scott Ananian pptp-1.8.0/Documentation/DESIGN.PPTP0000644000175000017500000000404112231702206015744 0ustar jamesjamespptp called as: pptp hostname [[pptp options] --] [pppd options] The pptp program does: gethostbyname([hostname]) to get ip number. Try to open unix domain socket at /var/run/pptp/ip.num.ber.here. If not found, launch call manager for that ip address. Call manager opens unix domain socket at /var/run/pptp/ip.num.ber.here, does: 1) Open connection to the ip address using port 1723 protocol. 2) accept unix domain socket connection. [wait for any pptp call request to this ip] 3) On receiving a connection, open CALL to ip.address using port 1723. 2) send callID over unix domain socket for gre encapsulation. 3) Keepalive the socket. When either side closes socket, send call-close message to ip.address using port 1723. 4) on close of last call, send connection close using port 1723, close the unix domain socket at /var/run/pptp/ip.num.ber.here, and exit. Once call manager is opened (fork when done to return status to parent), the main process forks. Parent) launch gre-copy task. Holds call manager socket. Child) launch pppd with command-line options. Killing any of the three threads should cleanly shutdown system. HOW? Send pid of parent and child to call manager after fork over Unix-domain socket. Alternatively pptp may be launched by pppd. One advantage is that many existing tools for managing serial ppp connections can be used with pptp connections as well. Another is some pppd options can only be used this way. In particular the options "persist" and "demand" may be of use. Add the following option to your pppd options script: pty "/pptp hostname --nolaunchpppd [--phone phone-nr]" and start the connection like any other pppd connection. Note that old versions of pppd may not support the pty option. The following options are understood by pptp: --phone phone-number Specify the phone number for the connection. This is required by a number of ADSL services. --nolaunchpppd Needed if pptp is to be launched by pppd. See above pptp-1.8.0/Documentation/DESIGN.CALLMGR0000644000175000017500000000152412231702206016245 0ustar jamesjamesCall Manager is a single-threaded application. It's easier that way. Nothing blocks except a select() call. The pptp code provides an fd_set for us to watch, and a function to call to see if a given event pertains to the pptp code. Each CALL connection goes in the exceptions set, and is watched for close. We need a separate list of these, to check against the fd_set when an event happens. Writes get copied in a queue, and are only written if the select says we can. Reads go in another queue -- non-blocking! -- and messages are made from the queue as we are able. We register callbacks on significant events (any and all of them, if we please) which can trigger a close on a user unix socket, for example. Nomenclature: inet_read|write ... TCP port 1723 PPTP control connection unix_read|write ... Call manager Unix socket to pppd/gre. pptp-1.8.0/DEVELOPERS0000644000175000017500000000407612231702206013060 0ustar jamesjamesDevelopers Information Mailing List Subscribe to the pptpclient-devel mailing list if you intend to contribute to this project. On this mailing list we discuss problems and changes. https://lists.sourceforge.net/lists/listinfo/pptpclient-devel Patches You may send patches by e-mail, direct or to the mailing list, or if you have CVS commit rights, you may use them. Developers have permission (and encouragement) to adjust more than the file that they are submitting. Other files that may be adjusted are: ChangeLog documentation of changes at the code level. NEWS a history of changes as far as an end user is concerned. AUTHORS a list of people who want credit for contributions. TODO a list of things yet to be done. See section two of Eric Raymond's Software Release Practice HOWTO for some useful information on good patching practice. http://www.linuxdoc.org/HOWTO/Software-Release-Practice-HOWTO/ CVS Commits Mailing List Subscribe to the pptpclient-commits mailing list and you will receive messages from the CVS server when another developer commits. https://lists.sourceforge.net/lists/listinfo/pptpclient-commits CVS Tags There are two types of tags. Upstream source and release tags. Upstream source tags are set by the person who brings in the upstream version of ppp or ppp-mppe, and are not expected to move. This is because we are not the authoritative maintainer for those two packages; we're just generating a package ourselves. Upstream source tags at the moment are openssl-0_9_6 openssl-mppe-0_9_6 ppp-2_4_0 ppp-2_4_1 ppp-mppe-2_4_0 ppp-mppe-2_4_1 Release tags are set by the release engineer who makes the releases. Only he is to move these tags. Release tags at the moment are pptp-linux-1_0_3-1 pptp-linux-1_1_0-rc1 pptp-linux-1_1_0-rc2 pptp-linux-1_1_0-rc3 ppp-mppe-2_4_0-3 ppp-mppe-2_4_1-rc1 Internet Relay Chat Developers who use IRC on a regular basis are welcome to add the project's channel to their list of autojoin channels. Server: irc.freenode.net Channel: #pptp $Id: DEVELOPERS,v 1.4 2003/01/15 05:29:20 quozl Exp $ pptp-1.8.0/pqueue.c0000644000175000017500000001336212231702206013133 0ustar jamesjames#include #include #include #include #include "util.h" // for log() #include "pqueue.h" #ifdef DEBUG_PQUEUE #define DEBUG_ON 1 #else #define DEBUG_ON 0 #endif #define DEBUG_CMD(_a) if (DEBUG_ON) { _a } #define MIN_CAPACITY 128 /* min allocated buffer for a packet */ static int pqueue_alloc (u_int32_t seq, unsigned char *packet, int packlen, pqueue_t **new); int packet_timeout_usecs = DEFAULT_PACKET_TIMEOUT * 1000000; static pqueue_t *pq_head = NULL, *pq_tail = NULL; /* contains a list of free queue elements.*/ static pqueue_t *pq_freelist_head = NULL; static int pqueue_alloc(u_int32_t seq, unsigned char *packet, int packlen, pqueue_t **new) { pqueue_t *newent; DEBUG_CMD(log("seq=%d, packlen=%d", seq, packlen);); /* search the freelist for one that has sufficient space */ if (pq_freelist_head) { for (newent = pq_freelist_head; newent; newent = newent->next) { if (newent->capacity >= packlen) { /* unlink from freelist */ if (pq_freelist_head == newent) pq_freelist_head = newent->next; if (newent->prev) newent->prev->next = newent->next; if (newent->next) newent->next->prev = newent->prev; if (pq_freelist_head) pq_freelist_head->prev = NULL; break; } /* end if capacity >= packlen */ } /* end for */ /* nothing found? Take first and reallocate it */ if (NULL == newent) { newent = pq_freelist_head; pq_freelist_head = pq_freelist_head->next; if (pq_freelist_head) pq_freelist_head->prev = NULL; DEBUG_CMD(log("realloc capacity %d to %d",newent->capacity, packlen);); newent->packet = (unsigned char *)realloc(newent->packet, packlen); if (!newent->packet) { warn("error reallocating packet: %s", strerror(errno)); return -1; } newent->capacity = packlen; } DEBUG_CMD(log("Recycle entry from freelist. Capacity: %d", newent->capacity);); } else { /* allocate a new one */ newent = (pqueue_t *)malloc( sizeof(pqueue_t) ); if (!newent) { warn("error allocating newent: %s", strerror(errno)); return -1; } newent->capacity = 0; DEBUG_CMD(log("Alloc new queue entry");); } if ( ! newent->capacity ) { /* a new queue entry was allocated. Allocate the packet buffer */ int size = packlen < MIN_CAPACITY ? MIN_CAPACITY : packlen; /* Allocate at least MIN_CAPACITY */ DEBUG_CMD(log("allocating for packet size %d", size);); newent->packet = (unsigned char *)malloc(size); if (!newent->packet) { warn("error allocating packet: %s", strerror(errno)); return -1; } newent->capacity = size; } /* endif ! capacity */ assert( newent->capacity >= packlen ); /* store the contents into the buffer */ memcpy(newent->packet, packet, packlen); newent->next = newent->prev = NULL; newent->seq = seq; newent->packlen = packlen; gettimeofday(&newent->expires, NULL); newent->expires.tv_usec += packet_timeout_usecs; newent->expires.tv_sec += (newent->expires.tv_usec / 1000000); newent->expires.tv_usec %= 1000000; *new = newent; return 0; } int pqueue_add (u_int32_t seq, unsigned char *packet, int packlen) { pqueue_t *newent, *point; /* get a new entry */ if ( 0 != pqueue_alloc(seq, packet, packlen, &newent) ) { return -1; } for (point = pq_head; point != NULL; point = point->next) { if (point->seq == seq) { // queue already contains this packet warn("discarding duplicate packet %d", seq); return -1; } if (point->seq > seq) { // gone too far: point->seq > seq and point->prev->seq < seq if (point->prev) { // insert between point->prev and point DEBUG_CMD(log("adding %d between %d and %d", seq, point->prev->seq, point->seq);); point->prev->next = newent; } else { // insert at head of queue, before point DEBUG_CMD(log("adding %d before %d", seq, point->seq);); pq_head = newent; } newent->prev = point->prev; // will be NULL, at head of queue newent->next = point; point->prev = newent; return 0; } } /* We didn't find anywhere to insert the packet, * so there are no packets in the queue with higher sequences than this one, * so all the packets in the queue have lower sequences, * so this packet belongs at the end of the queue (which might be empty) */ if (pq_head == NULL) { DEBUG_CMD(log("adding %d to empty queue", seq);); pq_head = newent; } else { DEBUG_CMD(log("adding %d as tail, after %d", seq, pq_tail->seq);); pq_tail->next = newent; } newent->prev = pq_tail; pq_tail = newent; return 0; } int pqueue_del (pqueue_t *point) { DEBUG_CMD(log("Move seq %d to freelist", point->seq);); /* unlink from pq */ if (pq_head == point) pq_head = point->next; if (pq_tail == point) pq_tail = point->prev; if (point->prev) point->prev->next = point->next; if (point->next) point->next->prev = point->prev; /* add point to the freelist */ point->next = pq_freelist_head; point->prev = NULL; if (point->next) point->next->prev = point; pq_freelist_head = point; DEBUG_CMD( int pq_count = 0; int pq_freelist_count = 0; pqueue_t *point; for ( point = pq_head; point ; point = point->next) { ++pq_count; } for ( point = pq_freelist_head; point ; point = point->next) { ++pq_freelist_count; } log("queue length is %d, freelist length is %d", pq_count, pq_freelist_count); ); return 0; } pqueue_t *pqueue_head (void) { return pq_head; } int pqueue_expiry_time (pqueue_t *entry) { struct timeval tv; int expiry_time; gettimeofday(&tv, NULL); expiry_time = (entry->expires.tv_sec - tv.tv_sec) * 1000000; expiry_time += (entry->expires.tv_usec - tv.tv_usec); return expiry_time; } pptp-1.8.0/options.pptp0000644000175000017500000000414712231702206014064 0ustar jamesjames############################################################################### # $Id: options.pptp,v 1.4 2012/08/30 21:34:13 quozl Exp $ # # Sample PPTP PPP options file /etc/ppp/options.pptp # Options used by PPP when a connection is made by a PPTP client. # This file can be referred to by an /etc/ppp/peers file for the tunnel. # Changes are effective on the next connection. See "man pppd". # # You are expected to change this file to suit your system. As # packaged, it requires PPP 2.4.2 or later from http://ppp.samba.org/ # and the kernel MPPE module available from the CVS repository also on # http://ppp.samba.org/, which is packaged for DKMS as kernel_ppp_mppe. ############################################################################### # Lock the port lock # Authentication # We don't need the tunnel server to authenticate itself noauth # We won't do PAP, EAP, CHAP, or MSCHAP, but we will accept MSCHAP-V2 # (you may need to remove these refusals if the server is not using MPPE) refuse-pap refuse-eap refuse-chap refuse-mschap # Compression # Turn off compression protocols we know won't be used nobsdcomp nodeflate # Encryption # (There have been multiple versions of PPP with encryption support, # choose which of the following sections you will use. Note that MPPE # requires the use of MSCHAP-V2 during authentication) # # Note that using PPTP with MPPE and MSCHAP-V2 should be considered # insecure: # http://marc.info/?l=pptpclient-devel&m=134372640219039&w=2 # https://github.com/moxie0/chapcrack/blob/master/README.md # http://technet.microsoft.com/en-us/security/advisory/2743314 # http://ppp.samba.org/ the PPP project version of PPP by Paul Mackarras # ppp-2.4.2 or later with MPPE only, kernel module ppp_mppe.o # If the kernel is booted in FIPS mode (fips=1), the ppp_mppe.ko module # is not allowed and PPTP-MPPE is not available. # {{{ # Require MPPE 128-bit encryption #require-mppe-128 # }}} # http://mppe-mppc.alphacron.de/ fork from PPP project by Jan Dubiec # ppp-2.4.2 or later with MPPE and MPPC, kernel module ppp_mppe_mppc.o # {{{ # Require MPPE 128-bit encryption #mppe required,stateless # }}} pptp-1.8.0/TODO0000644000175000017500000000677712231702206012167 0ustar jamesjames18th September 2006 https://sourceforge.net/tracker/?func=detail&atid=407155&aid=1560433&group_id=33063 Feature request, add code to attempt multiple IPs in a round-robin DNS rotation. 12th September 2006 https://sourceforge.net/tracker/?func=detail&atid=407152&aid=1556506&group_id=33063 Add call-id as quirk or command-line option. 13th February 2006 pty write may block, which prevents read, according to patch #502930 on SourceForge. Generally a lack of flow control. We don't implement flow control well. 8th April 2005 On Thu, Apr 07, 2005 at 07:36:41AM -0700, Roark Hennessy wrote: > I find in order to get the tunnel working I have to do a > route add -host gateway dev +ethN > Can this be done automatically in the config somewhere? Not everybody needs this in order to get the tunnel working, it depends on the configuration of the server, and it is problematic calculating the correct route to add. However, the GUI PPTP client (pptpconfig) does this automatically, and when done unnecessarily it seems harmless. I'll take a patch that implements the same thing in C within pptp, so that people who don't use the GUI get it done for them. Here's what the pptpconfig.php program does; - the IP address of the PPTP server is obtained from the name, using gethostbyname(), - the command "ip route get $ip | head -1" is executed, where $ip is the IP address determined above, and the result of the command is stored; it is a route specification of the path to the server before the tunnel is started, - in routing_start(), an "ip route add" command is done using the route specification obtained above, - when the tunnel is shutdown, an "ip route del" command is done using the same route specification. I would prefer that the patch implements this by embedding the equivalent syscalls within the pptp program, rather than use system() or popen() to execute the /usr/sbin/ip program. I would also prefer that there be a command line option for disabling the feature. -- 10th March 2005 - call manager is not being reused as it was designed to be; if a tunnel is started within a minute of a tunnel being stopped, it does not succeed; symptom is LCP ConfReq's without any traffic from the server. -- - finish --max-echo-wait 11th August 2004 - add two configurable timeouts for echo generation and echo reply timeout, requested by Tobias Brox. - ship .spec with tarball. 13th February 2004 - timeout connect earlier, with option to extend timeout. 20th May 2003 - GRE stats to a pipe or shared memory, for GUI to use 15th February 2003 - pptp.8 update man page for new options - pptp.c long_options array should use NULL for second last arg, not 0 - pptp.c use getopt_long more simply, e.g. set flags in option array 1st May 2002 - log failure of write() to raw socket, as Ryan Murray has encountered an EPERM situation that was not being logged. 12th February 2002 - clean up -T errors in pptp-command, 23rd December 2000 Things to do: Autoconf/automake this beastie. Fix do_gre_copy semantics to properly handle multiple calls. Like the call manager, there should only be one gre-copy process per connection. This process needs to funnel packets to different output tty's, though, depending on the call-id embedded in the GRE encapsulation. pptp.c must then be modified to use an already-existing gre-copy process in the same way it uses an already-existing call manager. $Id: TODO,v 1.29 2006/09/18 01:50:05 quozl Exp $ pptp-1.8.0/pptp_gre.h0000644000175000017500000000372012231702206013451 0ustar jamesjames/* pptp_gre.h -- encapsulate PPP in PPTP-GRE. * Handle the IP Protocol 47 portion of PPTP. * C. Scott Ananian * * $Id: pptp_gre.h,v 1.6 2008/02/19 05:05:03 quozl Exp $ */ #include "pptp_compat.h" int pptp_gre_bind(struct in_addr inetaddr); void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id, int pty_fd, int gre_fd); extern int syncppp; extern int disable_buffer; typedef struct pack_track { uint32_t seq; // seq no of this tracked packet uint64_t time; // time when this tracked packet was sent (in usecs) } pack_track_t; typedef struct gre_stats { /* statistics for GRE receive */ uint32_t rx_accepted; // data packet was passed to pppd uint32_t rx_lost; // data packet did not arrive before timeout uint32_t rx_underwin; // data packet was under window (arrived too late // or duplicate packet) uint32_t rx_overwin; // data packet was over window // (too many packets lost?) uint32_t rx_buffered; // data packet arrived earlier than expected, // packet(s) before it were lost or reordered uint32_t rx_errors; // OS error on receive uint32_t rx_truncated; // truncated packet uint32_t rx_invalid; // wrong protocol or invalid flags uint32_t rx_acks; // acknowledgement only /* statistics for GRE transmit */ uint32_t tx_sent; // data packet write() to GRE socket succeeded uint32_t tx_failed; // data packet write() to GRE socket returned error uint32_t tx_short; // data packet write() to GRE socket underflowed uint32_t tx_acks; // sent packet with just ACK uint32_t tx_oversize; // data packet dropped because it was too large /* statistics for packet tracking, for RTT calculation */ pack_track_t pt; // last data packet seq/time int rtt; // estimated round-trip time in us } gre_stats_t; extern gre_stats_t stats; pptp-1.8.0/pptp_callmgr.c0000644000175000017500000003441112231702206014311 0ustar jamesjames/* pptp_callmgr.c ... Call manager for PPTP connections. * Handles TCP port 1723 protocol. * C. Scott Ananian * * $Id: pptp_callmgr.c,v 1.27 2011/12/19 07:18:09 quozl Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #if defined (__SVR4) && defined (__sun) #include #endif #include #include #include #include #include "pptp_callmgr.h" #include "pptp_ctrl.h" #include "pptp_msg.h" #include "dirutil.h" #include "vector.h" #include "util.h" #include "routing.h" extern struct in_addr localbind; /* from pptp.c */ extern int rtmark; extern int nohostroute; int open_inetsock(struct in_addr inetaddr); int open_unixsock(struct in_addr inetaddr); void close_inetsock(int fd, struct in_addr inetaddr); void close_unixsock(int fd, struct in_addr inetaddr); sigjmp_buf callmgr_env; void callmgr_sighandler(int sig __attribute__ ((unused))) { /* TODO: according to signal(2), siglongjmp() is unsafe used here */ siglongjmp (callmgr_env, 1); } void callmgr_do_nothing(int sig __attribute__ ((unused))) { /* do nothing signal handler */ } struct local_callinfo { int unix_sock; pid_t pid[2]; }; struct local_conninfo { VECTOR * call_list; fd_set * call_set; }; /* Call callback */ void call_callback(PPTP_CONN *conn, PPTP_CALL *call, enum call_state state) { struct local_callinfo *lci; struct local_conninfo *conninfo; u_int16_t call_id[2]; switch(state) { case CALL_OPEN_DONE: /* okey dokey. This means that the call_id and peer_call_id are * now valid, so lets send them on to our friends who requested * this call. */ lci = pptp_call_closure_get(conn, call); assert(lci != NULL); pptp_call_get_ids(conn, call, &call_id[0], &call_id[1]); write(lci->unix_sock, &call_id, sizeof(call_id)); /* Our duty to the fatherland is now complete. */ break; case CALL_OPEN_FAIL: case CALL_CLOSE_RQST: case CALL_CLOSE_DONE: /* don't need to do anything here, except make sure tables * are sync'ed */ log("Closing connection (call state)"); conninfo = pptp_conn_closure_get(conn); lci = pptp_call_closure_get(conn, call); assert(lci != NULL && conninfo != NULL); if (vector_contains(conninfo->call_list, lci->unix_sock)) { vector_remove(conninfo->call_list, lci->unix_sock); close(lci->unix_sock); FD_CLR(lci->unix_sock, conninfo->call_set); if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM); if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM); } break; default: log("Unhandled call callback state [%d].", (int) state); break; } } /****************************************************************************** * NOTE ABOUT 'VOLATILE': * several variables here get a volatile qualifier to silence warnings * from older (before 3.0) gccs. if the longjmp stuff is removed, * the volatile qualifiers should be removed as well. *****************************************************************************/ /*** Call Manager *************************************************************/ int callmgr_main(int argc, char **argv, char **envp __attribute__ ((unused))) { struct in_addr inetaddr; int inet_sock, unix_sock; fd_set call_set; PPTP_CONN * conn; VECTOR * call_list; int max_fd = 0; volatile int first = 1; int retval; int i; char * volatile phonenr; /* Step 0: Check arguments */ if (argc < 2) fatal("Usage: %s ip.add.ress.here [--phone ]", argv[0]); phonenr = argc == 3 ? argv[2] : NULL; if (inet_aton(argv[1], &inetaddr) == 0) fatal("Invalid IP address: %s", argv[1]); if (!nohostroute) { routing_init(inet_ntoa(inetaddr)); routing_start(); } /* Step 1: Open sockets. */ if ((inet_sock = open_inetsock(inetaddr)) < 0) fatal("Could not open control connection to %s", argv[1]); if ((unix_sock = open_unixsock(inetaddr)) < 0) fatal("Could not open unix socket for %s", argv[1]); /* Step 1b: FORK and return status to calling process. */ switch (fork()) { case 0: /* child. stick around. */ break; case -1: /* failure. Fatal. */ fatal("Could not fork."); default: /* Parent. Return status to caller. */ exit(0); } /* re-open stderr as /dev/null to release it */ file2fd("/dev/null", "wb", STDERR_FILENO); /* Step 1c: Clean up unix socket on TERM */ if (sigsetjmp(callmgr_env, 1) != 0) goto cleanup; signal(SIGINT, callmgr_sighandler); signal(SIGTERM, callmgr_sighandler); signal(SIGPIPE, callmgr_do_nothing); signal(SIGUSR1, callmgr_do_nothing); /* signal state change wake up accept */ /* Step 2: Open control connection and register callback */ if ((conn = pptp_conn_open(inet_sock, 1, NULL/* callback */)) == NULL) { close(unix_sock); close(inet_sock); fatal("Could not open connection."); } FD_ZERO(&call_set); call_list = vector_create(); { struct local_conninfo *conninfo = malloc(sizeof(*conninfo)); if (conninfo == NULL) { close(unix_sock); close(inet_sock); fatal("No memory."); } conninfo->call_list = call_list; conninfo->call_set = &call_set; pptp_conn_closure_put(conn, conninfo); } if (sigsetjmp(callmgr_env, 1) != 0) goto shutdown; /* Step 3: Get FD_SETs */ max_fd = unix_sock; do { int rc; fd_set read_set = call_set, write_set; if (pptp_conn_is_dead(conn)) break; FD_ZERO (&write_set); if (pptp_conn_established(conn)) { FD_SET (unix_sock, &read_set); if (unix_sock > max_fd) max_fd = unix_sock; } pptp_fd_set(conn, &read_set, &write_set, &max_fd); for (; max_fd > 0 ; max_fd--) { if (FD_ISSET (max_fd, &read_set) || FD_ISSET (max_fd, &write_set)) break; } /* Step 4: Wait on INET or UNIX event */ if ((rc = select(max_fd + 1, &read_set, &write_set, NULL, NULL)) <0) { if (errno == EBADF) break; /* a signal or somesuch. */ continue; } /* Step 5a: Handle INET events */ rc = pptp_dispatch(conn, &read_set, &write_set); if (rc < 0) break; /* Step 5b: Handle new connection to UNIX socket */ if (FD_ISSET(unix_sock, &read_set)) { /* New call! */ union { struct sockaddr a; struct sockaddr_un u; } from; socklen_t len = sizeof(from.u); PPTP_CALL * call; struct local_callinfo *lci; int s; /* Accept the socket */ FD_CLR (unix_sock, &read_set); if ((s = accept(unix_sock, &from.a, &len)) < 0) { warn("Socket not accepted: %s", strerror(errno)); goto skip_accept; } /* Allocate memory for local call information structure. */ if ((lci = malloc(sizeof(*lci))) == NULL) { warn("Out of memory."); close(s); goto skip_accept; } lci->unix_sock = s; /* Give the initiator time to write the PIDs while we open * the call */ call = pptp_call_open(conn, call_callback, phonenr); /* Read and store the associated pids */ read(s, &lci->pid[0], sizeof(lci->pid[0])); read(s, &lci->pid[1], sizeof(lci->pid[1])); /* associate the local information with the call */ pptp_call_closure_put(conn, call, (void *) lci); /* The rest is done on callback. */ /* Keep alive; wait for close */ retval = vector_insert(call_list, s, call); assert(retval); if (s > max_fd) max_fd = s; FD_SET(s, &call_set); first = 0; } skip_accept: /* Step 5c: Handle socket close */ for (i = 0; i < max_fd + 1; i++) if (FD_ISSET(i, &read_set)) { /* close it */ PPTP_CALL * call; retval = vector_search(call_list, i, &call); if (retval) { struct local_callinfo *lci = pptp_call_closure_get(conn, call); log("Closing connection (unhandled)"); if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM); if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM); free(lci); /* soft shutdown. Callback will do hard shutdown later */ pptp_call_close(conn, call); vector_remove(call_list, i); } FD_CLR(i, &call_set); close(i); } } while (vector_size(call_list) > 0 || first); shutdown: { int rc; fd_set read_set, write_set; struct timeval tv; signal(SIGINT, callmgr_do_nothing); signal(SIGTERM, callmgr_do_nothing); /* warn("Shutdown"); */ /* kill all open calls */ for (i = 0; i < vector_size(call_list); i++) { PPTP_CALL *call = vector_get_Nth(call_list, i); struct local_callinfo *lci = pptp_call_closure_get(conn, call); log("Closing connection (shutdown)"); pptp_call_close(conn, call); if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM); if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM); } /* attempt to dispatch these messages */ FD_ZERO(&read_set); FD_ZERO(&write_set); pptp_fd_set(conn, &read_set, &write_set, &max_fd); tv.tv_sec = 0; tv.tv_usec = 0; select(max_fd + 1, &read_set, &write_set, NULL, &tv); rc = pptp_dispatch(conn, &read_set, &write_set); if (rc > 0) { /* wait for a respond, a timeout because there might not be one */ FD_ZERO(&read_set); FD_ZERO(&write_set); pptp_fd_set(conn, &read_set, &write_set, &max_fd); tv.tv_sec = 2; tv.tv_usec = 0; select(max_fd + 1, &read_set, &write_set, NULL, &tv); rc = pptp_dispatch(conn, &read_set, &write_set); if (rc > 0) { if (i > 0) sleep(2); /* no more open calls. Close the connection. */ pptp_conn_close(conn, PPTP_STOP_LOCAL_SHUTDOWN); /* wait for a respond, a timeout because there might not be one */ FD_ZERO(&read_set); FD_ZERO(&write_set); pptp_fd_set(conn, &read_set, &write_set, &max_fd); tv.tv_sec = 2; tv.tv_usec = 0; select(max_fd + 1, &read_set, &write_set, NULL, &tv); pptp_dispatch(conn, &read_set, &write_set); if (rc > 0) sleep(2); } } /* with extreme prejudice */ pptp_conn_destroy(conn); pptp_conn_free(conn); vector_destroy(call_list); } cleanup: signal(SIGINT, callmgr_do_nothing); signal(SIGTERM, callmgr_do_nothing); close_inetsock(inet_sock, inetaddr); close_unixsock(unix_sock, inetaddr); return 0; } /*** open_inetsock ************************************************************/ int open_inetsock(struct in_addr inetaddr) { union { struct sockaddr a; struct sockaddr_in i; } dest, src; int s; dest.i.sin_family = AF_INET; dest.i.sin_port = htons(PPTP_PORT); dest.i.sin_addr = inetaddr; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { warn("socket: %s", strerror(errno)); return s; } #ifdef SO_MARK if (rtmark) { if (setsockopt(s, SOL_SOCKET, SO_MARK, &rtmark, sizeof(rtmark))) { warn("setsockopt(SO_MARK): %s", strerror(errno)); close(s); return -1; } } #endif if (localbind.s_addr != INADDR_NONE) { bzero(&src, sizeof(src)); src.i.sin_family = AF_INET; src.i.sin_addr = localbind; if (bind(s, &src.a, sizeof(src.i)) != 0) { warn("bind: %s", strerror(errno)); close(s); return -1; } } if (connect(s, &dest.a, sizeof(dest.i)) < 0) { warn("connect: %s", strerror(errno)); close(s); return -1; } return s; } /*** open_unixsock ************************************************************/ int open_unixsock(struct in_addr inetaddr) { union { struct sockaddr a; struct sockaddr_un u; } where; struct stat st; char *dir; int s; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { warn("socket: %s", strerror(errno)); return s; } callmgr_name_unixsock( &where.u, inetaddr, localbind); if (stat(where.u.sun_path, &st) >= 0) { warn("Call manager for %s is already running.", inet_ntoa(inetaddr)); close(s); return -1; } /* Make sure path is valid. */ dir = dirname(where.u.sun_path); if (!make_valid_path(dir, 0770)) fatal("Could not make path to %s: %s", where.u.sun_path, strerror(errno)); free(dir); if (bind(s, &where.a, sizeof(where.u)) < 0) { warn("bind: %s", strerror(errno)); close(s); return -1; } chmod(where.u.sun_path, 0777); listen(s, 127); return s; } /*** close_inetsock ***********************************************************/ void close_inetsock(int fd, struct in_addr inetaddr __attribute__ ((unused))) { close(fd); } /*** close_unixsock ***********************************************************/ void close_unixsock(int fd, struct in_addr inetaddr) { struct sockaddr_un where; close(fd); callmgr_name_unixsock(&where, inetaddr, localbind); unlink(where.sun_path); } /*** make a unix socket address ***********************************************/ void callmgr_name_unixsock(struct sockaddr_un *where, struct in_addr inetaddr, struct in_addr localbind) { char localaddr[16], remoteaddr[16]; where->sun_family = AF_UNIX; strncpy(localaddr, inet_ntoa(localbind), 16); strncpy(remoteaddr, inet_ntoa(inetaddr), 16); snprintf(where->sun_path, sizeof(where->sun_path), PPTP_SOCKET_PREFIX "%s:%s", localaddr, remoteaddr); } pptp-1.8.0/util.c0000644000175000017500000000717512231702206012611 0ustar jamesjames/* util.c ....... error message utilities. * C. Scott Ananian * * $Id: util.c,v 1.13 2011/12/19 07:15:03 quozl Exp $ */ #include #include #include #include #include #include "util.h" #ifndef PROGRAM_NAME #define PROGRAM_NAME "pptp" #endif /* implementation of log_string, defined as extern in util.h */ const char *log_string = "anon"; static void open_log(void) __attribute__ ((constructor)); static void close_log(void) __attribute__ ((destructor)); #define MAKE_STRING(label) \ va_list ap; \ char buf[256], string[256]; \ va_start(ap, format); \ vsnprintf(buf, sizeof(buf), format, ap); \ snprintf(string, sizeof(string), "%s %s[%s:%s:%d]: %s", \ log_string, label, func, file, line, buf); \ va_end(ap) /*** open log *****************************************************************/ static void open_log(void) { openlog(PROGRAM_NAME, LOG_PID, LOG_DAEMON); } /*** close log ****************************************************************/ static void close_log(void) { closelog(); } /*** print a message to syslog ************************************************/ void _log(const char *func, const char *file, int line, const char *format, ...) { MAKE_STRING("log"); syslog(LOG_NOTICE, "%s", string); } /*** print a warning to syslog ************************************************/ void _warn(const char *func, const char *file, int line, const char *format, ...) { MAKE_STRING("warn"); fprintf(stderr, "%s\n", string); syslog(LOG_WARNING, "%s", string); } /*** print a fatal warning to syslog and exit *********************************/ void _fatal(const char *func, const char *file, int line, const char *format, ...) { MAKE_STRING("fatal"); fprintf(stderr, "%s\n", string); syslog(LOG_CRIT, "%s", string); exit(1); } /*** connect a file to a file descriptor **************************************/ int file2fd(const char *path, const char *mode, int fd) { int ok = 0; FILE *file = NULL; file = fopen(path, mode); if (file != NULL && dup2(fileno(file), fd) != -1) ok = 1; if (file) fclose(file); return ok; } /* signal to pipe delivery implementation */ #include #include #include #include /* pipe private to process */ static int sigpipe[2]; /* create a signal pipe, returns 0 for success, -1 with errno for failure */ int sigpipe_create(void) { int rc; rc = pipe(sigpipe); if (rc < 0) return rc; fcntl(sigpipe[0], F_SETFD, FD_CLOEXEC); fcntl(sigpipe[1], F_SETFD, FD_CLOEXEC); #ifdef O_NONBLOCK #define FLAG_TO_SET O_NONBLOCK #else #ifdef SYSV #define FLAG_TO_SET O_NDELAY #else /* BSD */ #define FLAG_TO_SET FNDELAY #endif #endif rc = fcntl(sigpipe[1], F_GETFL); if (rc != -1) rc = fcntl(sigpipe[1], F_SETFL, rc | FLAG_TO_SET); if (rc < 0) return rc; return 0; #undef FLAG_TO_SET } /* generic handler for signals, writes signal number to pipe */ void sigpipe_handler(int signum) { write(sigpipe[1], &signum, sizeof(signum)); signal(signum, sigpipe_handler); } /* assign a signal number to the pipe */ void sigpipe_assign(int signum) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigpipe_handler; sigaction(signum, &sa, NULL); } /* return the signal pipe read file descriptor for select(2) */ int sigpipe_fd(void) { return sigpipe[0]; } /* read and return the pending signal from the pipe */ int sigpipe_read(void) { int signum; read(sigpipe[0], &signum, sizeof(signum)); return signum; } void sigpipe_close(void) { close(sigpipe[0]); close(sigpipe[1]); } pptp-1.8.0/vector.h0000644000175000017500000000205112231702206013127 0ustar jamesjames/* vector.h ..... store a vector of PPTP_CALL information and search it * efficiently. * C. Scott Ananian * * $Id: vector.h,v 1.2 2011/12/19 07:15:03 quozl Exp $ */ #ifndef INC_VECTOR_H #define INC_VECTOR_H #include "pptp_ctrl.h" /* for definition of PPTP_CALL */ typedef struct vector_struct VECTOR; VECTOR *vector_create(void); void vector_destroy(VECTOR *v); int vector_size(VECTOR *v); /* vector_insert and vector_search return TRUE on success, FALSE on failure. */ int vector_insert(VECTOR *v, int key, PPTP_CALL * call); int vector_remove(VECTOR *v, int key); int vector_search(VECTOR *v, int key, PPTP_CALL ** call); /* vector_contains returns FALSE if not found, TRUE if found. */ int vector_contains(VECTOR *v, int key); /* find first unused key. Returns TRUE on success, FALSE if no. */ int vector_scan(VECTOR *v, int lo, int hi, int *key); /* get a specific PPTP_CALL ... useful only when iterating. */ PPTP_CALL * vector_get_Nth(VECTOR *v, int n); #endif /* INC_VECTOR_H */ pptp-1.8.0/README0000644000175000017500000000363312231702206012343 0ustar jamesjamespptp pptp is an implementation of the PPTP protocol for Linux and other Unix systems. Copyright (C) 2000 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. You can find notes on installing in the file INSTALL, usage notes in the file USING, design notes in the Documentation directory, and the standards documents used to implement pptp can be found in the Reference directory. New versions and additional documentation can be found on the PPTP Client project page, at http://pptpclient.sourceforge.net/ Discussion of this code occurs on the mailing list for the PPTP Client project on SourceForge. To subscribe, visit the project's mailing lists page, or http://lists.sourceforge.net/lists/listinfo/pptpclient-devel Discussion of this code used to occur on the mailing list pptp@debs.fuller.edu, subscribe by sending "subscribe" in the body on an email to pptp-request@debs.fuller.edu, or look at http://debs.fuller.edu. Christoph Lameter was the list organizer. Re-organization and patches are of course greatly welcomed. See the file TODO. James Cameron (maintainer, release engineer) C. Scott Ananian (original author) $Id: README,v 1.6 2011/11/10 23:31:27 quozl Exp $ pptp-1.8.0/pptp_msg.h0000644000175000017500000003243612231702206013470 0ustar jamesjames/* pptp.h: packet structures and magic constants for the PPTP protocol * C. Scott Ananian * * $Id: pptp_msg.h,v 1.4 2008/02/19 05:05:03 quozl Exp $ */ #ifndef INC_PPTP_H #define INC_PPTP_H /* Grab definitions of int16, int32, etc. */ #include #include "pptp_compat.h" /* define "portable" htons, etc. */ #define hton8(x) (x) #define ntoh8(x) (x) #define hton16(x) htons(x) #define ntoh16(x) ntohs(x) #define hton32(x) htonl(x) #define ntoh32(x) ntohl(x) /* PPTP magic numbers: ----------------------------------------- */ #define PPTP_MAGIC 0x1A2B3C4D /* Magic cookie for PPTP datagrams */ #define PPTP_PORT 1723 /* PPTP TCP port number */ #define PPTP_PROTO 47 /* PPTP IP protocol number */ /* Control Connection Message Types: --------------------------- */ #define PPTP_MESSAGE_CONTROL 1 #define PPTP_MESSAGE_MANAGE 2 /* Control Message Types: -------------------------------------- */ /* (Control Connection Management) */ #define PPTP_START_CTRL_CONN_RQST 1 #define PPTP_START_CTRL_CONN_RPLY 2 #define PPTP_STOP_CTRL_CONN_RQST 3 #define PPTP_STOP_CTRL_CONN_RPLY 4 #define PPTP_ECHO_RQST 5 #define PPTP_ECHO_RPLY 6 /* (Call Management) */ #define PPTP_OUT_CALL_RQST 7 #define PPTP_OUT_CALL_RPLY 8 #define PPTP_IN_CALL_RQST 9 #define PPTP_IN_CALL_RPLY 10 #define PPTP_IN_CALL_CONNECT 11 #define PPTP_CALL_CLEAR_RQST 12 #define PPTP_CALL_CLEAR_NTFY 13 /* (Error Reporting) */ #define PPTP_WAN_ERR_NTFY 14 /* (PPP Session Control) */ #define PPTP_SET_LINK_INFO 15 /* PPTP version information: --------------------------------------*/ #define PPTP_VERSION_STRING "1.00" #define PPTP_VERSION 0x100 #define PPTP_FIRMWARE_STRING "0.01" #define PPTP_FIRMWARE_VERSION 0x001 /* PPTP capabilities: ---------------------------------------------*/ /* (Framing capabilities for msg sender) */ #define PPTP_FRAME_ASYNC 1 #define PPTP_FRAME_SYNC 2 #define PPTP_FRAME_ANY 3 /* (Bearer capabilities for msg sender) */ #define PPTP_BEARER_ANALOG 1 #define PPTP_BEARER_DIGITAL 2 #define PPTP_BEARER_ANY 3 #define PPTP_RESULT_GENERAL_ERROR 2 /* (Reasons to close a connection) */ #define PPTP_STOP_NONE 1 /* no good reason */ #define PPTP_STOP_PROTOCOL 2 /* can't support peer's protocol version */ #define PPTP_STOP_LOCAL_SHUTDOWN 3 /* requester is being shut down */ /* PPTP datagram structures (all data in network byte order): ----------*/ struct pptp_header { u_int16_t length; /* message length in octets, including header */ u_int16_t pptp_type; /* PPTP message type. 1 for control message. */ u_int32_t magic; /* this should be PPTP_MAGIC. */ u_int16_t ctrl_type; /* Control message type (0-15) */ u_int16_t reserved0; /* reserved. MUST BE ZERO. */ }; struct pptp_start_ctrl_conn { /* for control message types 1 and 2 */ struct pptp_header header; u_int16_t version; /* PPTP protocol version. = PPTP_VERSION */ u_int8_t result_code; /* these two fields should be zero on rqst msg*/ u_int8_t error_code; /* 0 unless result_code==2 (General Error) */ u_int32_t framing_cap; /* Framing capabilities */ u_int32_t bearer_cap; /* Bearer Capabilities */ u_int16_t max_channels; /* Maximum Channels (=0 for PNS, PAC ignores) */ u_int16_t firmware_rev; /* Firmware or Software Revision */ u_int8_t hostname[64]; /* Host Name (64 octets, zero terminated) */ u_int8_t vendor[64]; /* Vendor string (64 octets, zero term.) */ /* MS says that end of hostname/vendor fields should be filled with */ /* octets of value 0, but Win95 PPTP driver doesn't do this. */ }; struct pptp_stop_ctrl_conn { /* for control message types 3 and 4 */ struct pptp_header header; u_int8_t reason_result; /* reason for rqst, result for rply */ u_int8_t error_code; /* MUST be 0, unless rply result==2 (general err)*/ u_int16_t reserved1; /* MUST be 0 */ }; struct pptp_echo_rqst { /* for control message type 5 */ struct pptp_header header; u_int32_t identifier; /* arbitrary value set by sender which is used */ /* to match up reply and request */ }; struct pptp_echo_rply { /* for control message type 6 */ struct pptp_header header; u_int32_t identifier; /* should correspond to id of rqst */ u_int8_t result_code; u_int8_t error_code; /* =0, unless result_code==2 (general error) */ u_int16_t reserved1; /* MUST BE ZERO */ }; struct pptp_out_call_rqst { /* for control message type 7 */ struct pptp_header header; u_int16_t call_id; /* Call ID (unique id used to multiplex data) */ u_int16_t call_sernum; /* Call Serial Number (used for logging) */ u_int32_t bps_min; /* Minimum BPS (lowest acceptable line speed) */ u_int32_t bps_max; /* Maximum BPS (highest acceptable line speed) */ u_int32_t bearer; /* Bearer type */ u_int32_t framing; /* Framing type */ u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ u_int16_t phone_len; /* Phone Number Length (num. of valid digits) */ u_int16_t reserved1; /* MUST BE ZERO */ u_int8_t phone_num[64]; /* Phone Number (64 octets, null term.) */ u_int8_t subaddress[64]; /* Subaddress (64 octets, null term.) */ }; struct pptp_out_call_rply { /* for control message type 8 */ struct pptp_header header; u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ u_int8_t result_code; /* Result Code (1 is no errors) */ u_int8_t error_code; /* Error Code (=0 unless result_code==2) */ u_int16_t cause_code; /* Cause Code (addt'l failure information) */ u_int32_t speed; /* Connect Speed (in BPS) */ u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ u_int32_t channel; /* Physical Channel ID (for logging) */ }; struct pptp_in_call_rqst { /* for control message type 9 */ struct pptp_header header; u_int16_t call_id; /* Call ID (unique id used to multiplex data) */ u_int16_t call_sernum; /* Call Serial Number (used for logging) */ u_int32_t bearer; /* Bearer type */ u_int32_t channel; /* Physical Channel ID (for logging) */ u_int16_t dialed_len; /* Dialed Number Length (# of valid digits) */ u_int16_t dialing_len; /* Dialing Number Length (# of valid digits) */ u_int8_t dialed_num[64]; /* Dialed Number (64 octets, zero term.) */ u_int8_t dialing_num[64]; /* Dialing Number (64 octets, zero term.) */ u_int8_t subaddress[64]; /* Subaddress (64 octets, zero term.) */ }; struct pptp_in_call_rply { /* for control message type 10 */ struct pptp_header header; u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ u_int8_t result_code; /* Result Code (1 is no errors) */ u_int8_t error_code; /* Error Code (=0 unless result_code==2) */ u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ u_int16_t reserved1; /* MUST BE ZERO */ }; struct pptp_in_call_connect { /* for control message type 11 */ struct pptp_header header; u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ u_int16_t reserved1; /* MUST BE ZERO */ u_int32_t speed; /* Connect Speed (in BPS) */ u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ u_int32_t framing; /* Framing type */ }; struct pptp_call_clear_rqst { /* for control message type 12 */ struct pptp_header header; u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ u_int16_t reserved1; /* MUST BE ZERO */ }; struct pptp_call_clear_ntfy { /* for control message type 13 */ struct pptp_header header; u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ u_int8_t result_code; /* Result Code */ u_int8_t error_code; /* Error Code (=0 unless result_code==2) */ u_int16_t cause_code; /* Cause Code (for ISDN, is Q.931 cause code) */ u_int16_t reserved1; /* MUST BE ZERO */ u_int8_t call_stats[128]; /* Call Statistics: 128 octets, ascii, 0-term */ }; struct pptp_wan_err_ntfy { /* for control message type 14 */ struct pptp_header header; u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ u_int16_t reserved1; /* MUST BE ZERO */ u_int32_t crc_errors; /* CRC errors */ u_int32_t frame_errors; /* Framing errors */ u_int32_t hard_errors; /* Hardware overruns */ u_int32_t buff_errors; /* Buffer overruns */ u_int32_t time_errors; /* Time-out errors */ u_int32_t align_errors; /* Alignment errors */ }; struct pptp_set_link_info { /* for control message type 15 */ struct pptp_header header; u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst) */ u_int16_t reserved1; /* MUST BE ZERO */ u_int32_t send_accm; /* Send ACCM (for PPP packets; default 0xFFFFFFFF)*/ u_int32_t recv_accm; /* Receive ACCM (for PPP pack.;default 0xFFFFFFFF)*/ }; /* helpful #defines: -------------------------------------------- */ #define pptp_isvalid_ctrl(header, type, length) \ (!( ( ntoh16(((struct pptp_header *)header)->length) < (length) ) || \ ( ntoh16(((struct pptp_header *)header)->pptp_type) !=(type) ) || \ ( ntoh32(((struct pptp_header *)header)->magic) !=PPTP_MAGIC) || \ ( ntoh16(((struct pptp_header *)header)->ctrl_type) > PPTP_SET_LINK_INFO) || \ ( ntoh16(((struct pptp_header *)header)->reserved0) !=0 ) )) #define PPTP_HEADER_CTRL(type) \ { hton16(PPTP_CTRL_SIZE(type)), \ hton16(PPTP_MESSAGE_CONTROL), \ hton32(PPTP_MAGIC), \ hton16(type), 0 } #define PPTP_CTRL_SIZE(type) ( \ (type==PPTP_START_CTRL_CONN_RQST)?sizeof(struct pptp_start_ctrl_conn): \ (type==PPTP_START_CTRL_CONN_RPLY)?sizeof(struct pptp_start_ctrl_conn): \ (type==PPTP_STOP_CTRL_CONN_RQST )?sizeof(struct pptp_stop_ctrl_conn): \ (type==PPTP_STOP_CTRL_CONN_RPLY )?sizeof(struct pptp_stop_ctrl_conn): \ (type==PPTP_ECHO_RQST )?sizeof(struct pptp_echo_rqst): \ (type==PPTP_ECHO_RPLY )?sizeof(struct pptp_echo_rply): \ (type==PPTP_OUT_CALL_RQST )?sizeof(struct pptp_out_call_rqst): \ (type==PPTP_OUT_CALL_RPLY )?sizeof(struct pptp_out_call_rply): \ (type==PPTP_IN_CALL_RQST )?sizeof(struct pptp_in_call_rqst): \ (type==PPTP_IN_CALL_RPLY )?sizeof(struct pptp_in_call_rply): \ (type==PPTP_IN_CALL_CONNECT )?sizeof(struct pptp_in_call_connect): \ (type==PPTP_CALL_CLEAR_RQST )?sizeof(struct pptp_call_clear_rqst): \ (type==PPTP_CALL_CLEAR_NTFY )?sizeof(struct pptp_call_clear_ntfy): \ (type==PPTP_WAN_ERR_NTFY )?sizeof(struct pptp_wan_err_ntfy): \ (type==PPTP_SET_LINK_INFO )?sizeof(struct pptp_set_link_info): \ 0) #define max(a,b) (((a)>(b))?(a):(b)) #define PPTP_CTRL_SIZE_MAX ( \ max(sizeof(struct pptp_start_ctrl_conn), \ max(sizeof(struct pptp_echo_rqst), \ max(sizeof(struct pptp_echo_rply), \ max(sizeof(struct pptp_out_call_rqst), \ max(sizeof(struct pptp_out_call_rply), \ max(sizeof(struct pptp_in_call_rqst), \ max(sizeof(struct pptp_in_call_rply), \ max(sizeof(struct pptp_in_call_connect), \ max(sizeof(struct pptp_call_clear_rqst), \ max(sizeof(struct pptp_call_clear_ntfy), \ max(sizeof(struct pptp_wan_err_ntfy), \ max(sizeof(struct pptp_set_link_info), 0))))))))))))) /* gre header structure: -------------------------------------------- */ #define PPTP_GRE_PROTO 0x880B #define PPTP_GRE_VER 0x1 #define PPTP_GRE_FLAG_C 0x80 #define PPTP_GRE_FLAG_R 0x40 #define PPTP_GRE_FLAG_K 0x20 #define PPTP_GRE_FLAG_S 0x10 #define PPTP_GRE_FLAG_A 0x80 #define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C) #define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R) #define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K) #define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S) #define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A) struct pptp_gre_header { u_int8_t flags; /* bitfield */ u_int8_t ver; /* should be PPTP_GRE_VER (enhanced GRE) */ u_int16_t protocol; /* should be PPTP_GRE_PROTO (ppp-encaps) */ u_int16_t payload_len; /* size of ppp payload, not inc. gre header */ u_int16_t call_id; /* peer's call_id for this session */ u_int32_t seq; /* sequence number. Present if S==1 */ u_int32_t ack; /* seq number of highest packet recieved by */ /* sender in this session */ }; #endif /* INC_PPTP_H */ pptp-1.8.0/pptp_options.h0000644000175000017500000000231012231702206014361 0ustar jamesjames/* pptp_options.h ...... various constants used in the PPTP protocol. * #define STANDARD to emulate NT 4.0 exactly. * C. Scott Ananian * * $Id: pptp_options.h,v 1.3 2004/11/09 01:42:32 quozl Exp $ */ #ifndef INC_PPTP_OPTIONS_H #define INC_PPTP_OPTIONS_H #undef PPTP_FIRMWARE_STRING #undef PPTP_FIRMWARE_VERSION #define PPTP_BUF_MAX 65536 #define PPTP_TIMEOUT 60 /* seconds */ extern int idle_wait; extern int max_echo_wait; #define PPTP_CONNECT_SPEED 10000000 #define PPTP_WINDOW 3 #define PPTP_DELAY 0 #define PPTP_BPS_MIN 2400 #define PPTP_BPS_MAX 10000000 #ifndef STANDARD #define PPTP_MAX_CHANNELS 65535 #define PPTP_FIRMWARE_STRING "0.01" #define PPTP_FIRMWARE_VERSION 0x001 #define PPTP_HOSTNAME {'l','o','c','a','l',0} #define PPTP_VENDOR {'c','a','n','a','n','i','a','n',0} #define PPTP_FRAME_CAP PPTP_FRAME_ANY #define PPTP_BEARER_CAP PPTP_BEARER_ANY #else #define PPTP_MAX_CHANNELS 5 #define PPTP_FIRMWARE_STRING "0.01" #define PPTP_FIRMWARE_VERSION 0 #define PPTP_HOSTNAME {'l','o','c','a','l',0} #define PPTP_VENDOR {'N','T',0} #define PPTP_FRAME_CAP 2 #define PPTP_BEARER_CAP 1 #endif #endif /* INC_PPTP_OPTIONS_H */ pptp-1.8.0/PROTOCOL-SECURITY0000644000175000017500000001011212231702206014102 0ustar jamesjames Protocol Security Summary by Peter Mueller PPTP is known to be a faulty protocol. The designers of the protocol, Microsoft, recommend not to use it due to the inherent risks. Lots of people use PPTP anyway due to ease of use, but that doesn't mean it is any less hazardous. The maintainers of PPTP Client and Poptop recommend using OpenVPN (SSL based) or IPSec instead. (Posted on [1]2005-08-10 to the [2]mailing list) _________________________________________________________________ Why not use PPTP? by James Cameron The point to point tunneling protocol (PPTP) is not secure enough for some information security policies. It's the nature of the MSCHAP V2 authentication, how it can be broken trivially by capture of the datastream, and how MPPE depends on the MSCHAP tokens for cryptographic keys. MPPE is also only 128-bit, reasonably straightforward to attack, and the keys used at each end are the same, which lowers the effort required to succeed. The obvious lack of two-factor authentication, instead relying on a single username and password, is also a risk. The increasing use of domestic wireless systems makes information capture more likely. However, that doesn't mean people don't accept the risks. There are many corporations and individuals using PPTP with full knowledge of these risks. Some use mitigating controls, and some don't. Many people seem to judge the security of a protocol by the availability of the implementation, the ease of installation, or the level of documentation on our web site. Improving the documentation is the purpose of this web site, and we aren't doing that in order to say anything about the risks of the software! Any judgement of security should be rigorously applied to the design and implementation alone. PPTP on Linux, and Microsoft's PPTP, both implement fixes for vulnerabilities that were detected years ago in Microsoft's PPTP. But there remain the design vulnerabilities that cannot be fixed without changing the design. The changes needed would break interoperability. We can't change the Linux PPTP design, because it would stop working with Microsoft PPTP. They can't change their design, because it would stop working with all the other components out there, such as Nortel and Cisco, embedded routers, ADSL modems and their own Windows installed base. The only option then is to deprecate the product and promote the replacement. Microsoft promote something else. Our choice for Open Source systems is OpenVPN or IPsec. Level of acceptance isn't a good indicator of risk either. Some have said that the shipping of MSCHAP V2, MPPE and PPTP in Linux distributions is an indication of design security, but that's not the reason. It's for interoperability. As an example, see how Linux distributions still ship telnet, ftp, and rsh, even though these components are insecure because they reveal the password in cleartext in the network packets. The same can be said of many other components and packages. Our recommendations are; 1. do not implement PPTP between open source systems, because there's no justification, better security can be had from OpenVPN or IPsec, 2. do not implement PPTP servers unless the justification is that the clients must not have to install anything to get going (Microsoft PPTP is included already), and be aware of the risks of information interception, 3. do not implement PPTP clients unless the justification is that the server only provides PPTP, and there's nothing better that can be used, and again be aware of the risks of information interception. (Posted on [3]2005-08-10 to the [2]mailing list) References 1. http://marc.theaimsgroup.com/?l=poptop-server&m=112369621702624&w=2 2. http://pptpclient.sourceforge.net/contact.phtml#list 3. http://marc.theaimsgroup.com/?l=poptop-server&m=112365342910897&w=2 pptp-1.8.0/pptp.80000644000175000017500000001727212231702206012543 0ustar jamesjames.\" SH section heading .\" SS subsection heading .\" LP paragraph .\" IP indented paragraph .\" TP hanging label .TH PPTP 8 .\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection .\" other parms are allowed: see man(7), man(1) .SH NAME pptp \- PPTP driver .SH SYNOPSIS .B pptp .I " [ppp-options] ..." .SH "DESCRIPTION" .LP .B pptp establishes the client side of a Virtual Private Network (VPN) using the Point-to-Point Tunneling Protocol (PPTP). Use this program to connect to an employer's PPTP based VPN, or to certain cable and ADSL service providers. .LP By default, \fBpptp\fR establishes the PPTP call to the PPTP server, and then starts an instance of \fBpppd\fR to manage the data transfer. However, \fBpptp\fR can also be run as a connection manager within \fBpppd\fR. .SH OPTIONS .LP The first non\-option argument on the \fBpptp\fR command line must be the host name or IP address of the PPTP server. .LP All long options (starting with "\-\-") are interpreted as pptp options, and a fatal error occurs if an unrecognised option is used. .LP All command\-line arguments which do not start with "\-" are interpreted as ppp options, and passed as is to \fBpppd\fR unless \fB\-\-nolaunchpppd\fR is given. .TP .B \-\-phone Pass to remote host as phone number .TP .B \-\-nolaunchpppd Do not launch .B pppd but use stdin as the network connection. Use this flag when including .B pptp as a .B pppd connection process using the .B pty option. See EXAMPLES. .TP .B \-\-quirks Work around a buggy PPTP implementation, adopts special case handling for particular PPTP servers and ADSL modems. Currently recognised values are BEZEQ_ISRAEL only .TP .B \-\-debug Run in foreground (for debugging with gdb) .TP .B \-\-sync Enable Synchronous HDLC (pppd must use it too) .TP .B \-\-timeout Time to wait for reordered packets (0.01 to 10 secs) .TP .B \-\-nobuffer Completely disables buffering and reordering of packets. Any \-\-timeout specified will be ignored. .TP .B \-\-idle-wait Time to wait before sending a control connection echo request. The RFC2637 default is 60 seconds. .TP .B \-\-max-echo-wait Time to wait for an echo reply before closing the control connection. The RFC2637 default is 60 seconds. .TP .B \-\-logstring Use instead of 'anon' in syslog messages .TP .B \-\-localbind Bind to specified IP address instead of wildcard .TP .B \-\-rtmark Use specified policy routing mark for all packets. This causes both the TCP control connection's packets as well as the GRE packets to bear the given policy routing / netfilter mark. This can be used with .I ip rule (from iproute2) to use a separate routing table for the pptp client. (requires root privileges or the CAP_NET_ADMIN capability.) .TP .B \-\-nohostroute Do not configure a host route pointing towards the PPTP server. (cf. ROUTING below) .TP .B \-\-loglevel Sets the debugging level (0=low, 1=default, 2=high) .TP .B \-\-test-type Enable packet reordering tests that damage the integrity of the packet stream to the server. Use this only when testing servers. Zero is the default, and means that packets are sent in the correct order. A value of one (1) causes a single swap between two packets, such that the sequence numbers might be 1 2 3 4 6 5 7 8 9. A value of two (2) causes ten packets to be buffered, then sent out of order but ascending, such that the sequence numbers might be 1 2 3 4 16 6 7 8 9 10 11 12 13 14 15 17 18 19 20. A value of three (3) causes ten packets to be buffered, then sent in the reverse order, like this; 1 2 3 4 16 15 14 13 12 11 10 9 8 7 6 5 17 18 19 20. .TP .B \-\-test-rate Sets the number of packets to pass before causing a reordering test. Default is 100. Has no effect if test-type is zero. The result of test types 2 and 3 are undefined if this value is less than ten. .SH "ROUTING" When PPTP is used in conjunction with a default route on top of the tunnel (or just any route encompassing the PPTP server), the mechanics of routing would cause the PPTP packets themselves to be routed over the tunnel. This would result in an encapsulation loop, destroying connectivity. .B pptp by default works around this by looking up the route towards the PPTP server at startup and configures a host route with that data. This essentially "freezes" routing for PPTP packets at the startup configuration. This behaviour can be disabled with .B --nohostroute if undesired (like when using .B --rtmark to implement policy routing). .B NB: the route added by .B pptp is currently not deleted at exit! .SH "QUIRKS" .TP .B BEZEQ_ISRAEL modifies packets to interoperate with Orckit ADSL modems on the BEZEQ network in Israel. .SH "EXAMPLES" .B Connection to a Microsoft Windows VPN Server .BR pppd noauth nobsdcomp nodeflate require\-mppe\-128 name domain\\\\\\\\username remotename PPTP pty "pptp 10.0.0.5 \-\-nolaunchpppd" .PP Note that the \fBchap\-secrets\fR file used by \fBpppd\fR must include an entry for domain\\\\username .SH "STATISTICS" The pptp process collects statistics when sending and receiving GRE packets. They are intended to be useful for debugging poor PPTP performance and for general monitoring of link quality. The statistics are cumulative since the pptp process was started. .PP The statistics can be viewed by sending a SIGUSR1 signal to the "GRE-to-PPP Gateway" process, which will cause it to dump them to the system logs (at the LOG_NOTICE level). A better way to present the statistics to applications is being sought (e.g. SNMP?). .PP The following statistics are collected at the time of writing (April 2003): .TP .B rx accepted the number of GRE packets successfully passed to PPP .TP .B rx lost the number of packets never received, and presumed lost in the network .TP .B rx under win the number of packets which were duplicates or had old sequence numbers (this might be caused by a packet-reordering network if your reordering timeout is set too low) .TP .B rx over win the number of packets which were too far ahead in the sequence to be reordered (might be caused by loss of more than 300 packets in a row) .TP .B rx buffered the number of packets which were slightly ahead of sequence, and were either buffered for reordering, or if buffering is disabled, accepted immediately (resulting in the intermediate packets being discarded). .TP .B rx OS errors the number of times where the operating system reported an error when we tried to read a packet .TP .B rx truncated the number of times we received a packet which was shorter than the length implied by the GRE header .TP .B rx invalid the number of times we received a packet which had invalid or unsupported flags set in the header, wrong version, or wrong protocol. .TP .B rx acks the number of pure acknowledgements received (without data). Too many of these will waste bandwidth, and might be solved by tuning the remote host. .TP .B tx sent the number of GRE packets sent with data .TP .B tx failed the number of packets we tried to send, but the OS reported an error .TP .B tx short the number of times the OS would not let us write a complete packet .TP .B tx acks the number of times we sent a pure ack, without data .TP .B tx oversize the number of times we couldn't send a packet because it was over PACKET_MAX bytes long .TP .B round trip the estimated round-trip time in milliseconds .SH "SEE ALSO" .IR pppd (8) .PP Documentation in .IR /usr/share/doc/pptp .SH AUTHOR This manual page was written by James Cameron from text contributed by Thomas Quinot , for the Debian GNU/Linux system. The description of the available statistics was written by Chris Wilson . Updates for the Debian distribution by Ola Lundqvist . pptp-1.8.0/pqueue.h0000644000175000017500000000143712231702206013140 0ustar jamesjames#ifndef PQUEUE_H #define PQUEUE_H #include #include /* wait this many seconds for missing packets before forgetting about them */ #define DEFAULT_PACKET_TIMEOUT 0.3 extern int packet_timeout_usecs; /* assume packet is bad/spoofed if it's more than this many seqs ahead */ #define MISSING_WINDOW 300 /* Packet queue structure: linked list of packets received out-of-order */ typedef struct pqueue { struct pqueue *next; struct pqueue *prev; u_int32_t seq; struct timeval expires; unsigned char *packet; int packlen; int capacity; } pqueue_t; int pqueue_add (u_int32_t seq, unsigned char *packet, int packlen); int pqueue_del (pqueue_t *point); pqueue_t *pqueue_head (void); int pqueue_expiry_time (pqueue_t *entry); #endif /* PQUEUE_H */ pptp-1.8.0/pptp.c0000644000175000017500000005135612231702206012617 0ustar jamesjames/* an implementation of the PPTP protocol Copyright (C) 2000 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. pptp.c ... client shell to launch call managers, data handlers, and the pppd from the command line. */ #include #include #if defined(__FreeBSD__) #include #elif defined(__NetBSD__) || defined(__OpenBSD__) #include #elif defined(__APPLE__) #include #elif defined (__SVR4) && defined (__sun) #else #include #endif #ifdef USER_PPP #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__APPLE__) #include "getopt.h" #else #include #endif #include #include "config.h" #include "pptp_callmgr.h" #include "pptp_gre.h" #include "version.h" #if defined(__linux__) #include #endif #include "inststr.h" #include "util.h" #include "pptp_quirks.h" #include "pqueue.h" #include "pptp_options.h" #include "pptp_compat.h" #ifndef PPPD_BINARY #define PPPD_BINARY "pppd" #endif int syncppp = 0; int log_level = 1; int disable_buffer = 0; int test_type = 0; int test_rate = 100; struct in_addr get_ip_address(char *name); int open_callmgr(struct in_addr inetaddr, char *phonenr, int argc,char **argv,char **envp, int pty_fd, int gre_fd); void launch_callmgr(struct in_addr inetaddr, char *phonenr, int argc,char **argv,char **envp); int get_call_id(int sock, pid_t gre, pid_t pppd, u_int16_t *call_id, u_int16_t *peer_call_id); void launch_pppd(char *ttydev, int argc, char **argv); /*** print usage and exit *****************************************************/ void usage(char *progname) { fprintf(stderr, "%s\n" "Copyright (C) 2000 Free Software Foundation\n\n" "This program comes with ABSOLUTELY NO WARRANTY; for details see source.\n" "This is free software, and you are welcome to redistribute it under certain\n" "conditions; see source for details.\n\n" "Usage:\n" " %s [] [[--] ]\n" "\n" "Or using pppd's pty option: \n" " pppd pty \"%s --nolaunchpppd \"\n" "\n" "Available pptp options:\n" " --version Display version number and exit\n" " --phone Pass to remote host as phone number\n" " --nolaunchpppd Do not launch pppd, for use as a pppd pty\n" " --quirks Work around a buggy PPTP implementation\n" " Currently recognised values are BEZEQ_ISRAEL only\n" " --debug Run in foreground (for debugging with gdb)\n" " --sync Enable Synchronous HDLC (pppd must use it too)\n" " --timeout Time to wait for reordered packets (0.01 to 10 secs)\n" " --nobuffer Disable packet buffering and reordering completely\n" " --idle-wait Time to wait before sending echo request\n" " --max-echo-wait Time to wait before giving up on lack of reply\n" " --logstring Use instead of 'anon' in syslog messages\n" " --localbind Bind to specified IP address instead of wildcard\n" #ifdef SO_MARK " --rtmark Use specified policy routing mark for all packets\n" #endif " --nohostroute Do not add host route towards \n" " --loglevel Sets the debugging level (0=low, 1=default, 2=high)\n" " --test-type Damage the packet stream by reordering\n" " --test-rate Do the test every n packets\n", version, progname, progname); log("%s called with wrong arguments, program not started.", progname); exit(1); } #if defined (__SVR4) && defined (__sun) struct in_addr localbind = { .s_addr = INADDR_ANY }; #else struct in_addr localbind = { INADDR_NONE }; #endif int rtmark = 0; int nohostroute = 0; static int signaled = 0; /*** do nothing signal handler ************************************************/ void do_nothing(int sig) { /* do nothing signal handler. Better than SIG_IGN. */ signaled = sig; } sigjmp_buf env; /*** signal handler ***********************************************************/ void sighandler(int sig __attribute__ ((unused))) { siglongjmp(env, 1); } /*** report statistics signal handler (SIGUSR1) *******************************/ void sigstats(int sig __attribute__ ((unused))) { syslog(LOG_NOTICE, "GRE statistics:\n"); #define LOG(name,value) syslog(LOG_NOTICE, name "\n", stats .value) LOG("rx accepted = %d", rx_accepted); LOG("rx lost = %d", rx_lost); LOG("rx under win = %d", rx_underwin); LOG("rx over win = %d", rx_overwin); LOG("rx buffered = %d", rx_buffered); LOG("rx OS errors = %d", rx_errors); LOG("rx truncated = %d", rx_truncated); LOG("rx invalid = %d", rx_invalid); LOG("rx acks = %d", rx_acks); LOG("tx sent = %d", tx_sent); LOG("tx failed = %d", tx_failed); LOG("tx short = %d", tx_short); LOG("tx acks = %d", tx_acks); LOG("tx oversize = %d", tx_oversize); LOG("round trip = %d usecs", rtt); #undef LOG } /*** main *********************************************************************/ /* TODO: redesign to avoid longjmp/setjmp. Several variables here have a volatile qualifier to silence warnings from gcc < 3.0. Remove the volatile qualifiers if longjmp/setjmp are removed. */ int main(int argc, char **argv, char **envp) { struct in_addr inetaddr; volatile int callmgr_sock = -1; char ttydev[PATH_MAX]; char *tty_name; int pty_fd, tty_fd, gre_fd, rc; volatile pid_t parent_pid, child_pid; u_int16_t call_id, peer_call_id; char buf[128]; int pppdargc; char **pppdargv; char phonenrbuf[65]; /* maximum length of field plus one for the trailing * '\0' */ char * volatile phonenr = NULL; volatile int launchpppd = 1, debug = 0; while(1){ /* structure with all recognised options for pptp */ static struct option long_options[] = { {"phone", 1, 0, 0}, {"nolaunchpppd", 0, 0, 0}, {"quirks", 1, 0, 0}, {"debug", 0, 0, 0}, {"sync", 0, 0, 0}, {"timeout", 1, 0, 0}, {"logstring", 1, 0, 0}, {"localbind", 1, 0, 0}, {"loglevel", 1, 0, 0}, {"nobuffer", 0, 0, 0}, {"idle-wait", 1, 0, 0}, {"max-echo-wait", 1, 0, 0}, {"version", 0, 0, 0}, {"test-type", 1, 0, 0}, {"test-rate", 1, 0, 0}, {"rtmark", 1, 0, 0}, {"nohostroute", 0, 0, 0}, {0, 0, 0, 0} }; int option_index = 0; int c; c = getopt_long (argc, argv, "", long_options, &option_index); if (c == -1) break; /* no more options */ switch (c) { case 0: if (option_index == 0) { /* --phone specified */ /* copy it to a buffer, as the argv's will be overwritten * by inststr() */ strncpy(phonenrbuf,optarg,sizeof(phonenrbuf)); phonenrbuf[sizeof(phonenrbuf) - 1] = '\0'; phonenr = phonenrbuf; } else if (option_index == 1) {/* --nolaunchpppd specified */ launchpppd = 0; } else if (option_index == 2) {/* --quirks specified */ if (set_quirk_index(find_quirk(optarg))) usage(argv[0]); } else if (option_index == 3) {/* --debug */ debug = 1; } else if (option_index == 4) {/* --sync specified */ syncppp = 1; } else if (option_index == 5) {/* --timeout */ float new_packet_timeout = atof(optarg); if (new_packet_timeout < 0.0099 || new_packet_timeout > 10) { fprintf(stderr, "Packet timeout %s (%f) out of range: " "should be between 0.01 and 10 seconds\n", optarg, new_packet_timeout); log("Packet timeout %s (%f) out of range: should be" "between 0.01 and 10 seconds", optarg, new_packet_timeout); exit(2); } else { packet_timeout_usecs = new_packet_timeout * 1000000; } } else if (option_index == 6) {/* --logstring */ log_string = strdup(optarg); } else if (option_index == 7) {/* --localbind */ if (inet_pton(AF_INET, optarg, (void *) &localbind) < 1) { fprintf(stderr, "Local bind address %s invalid\n", optarg); log("Local bind address %s invalid\n", optarg); exit(2); } } else if (option_index == 8) { /* --loglevel */ log_level = atoi(optarg); if (log_level < 0 || log_level > 2) usage(argv[0]); } else if (option_index == 9) { /* --nobuffer */ disable_buffer = 1; } else if (option_index == 10) { /* --idle-wait */ int x = atoi(optarg); if (x < 0) { fprintf(stderr, "--idle-wait must not be negative\n"); log("--idle-wait must not be negative\n"); exit(2); } else { idle_wait = x; } } else if (option_index == 11) { /* --max-echo-wait */ int x = atoi(optarg); if (x < 0) { fprintf(stderr, "--max-echo-wait must not be negative\n"); log("--max-echo-wait must not be negative\n"); exit(2); } else { max_echo_wait = x; } fprintf(stderr, "--max-echo-wait ignored, not yet implemented\n"); } else if (option_index == 12) { /* --version */ fprintf(stdout, "%s\n", version); exit(0); } else if (option_index == 13) { /* --test-type */ test_type = atoi(optarg); } else if (option_index == 14) { /* --test-rate */ test_rate = atoi(optarg); } else if (option_index == 15) { /* --rtmark */ #ifdef SO_MARK rtmark = atoi(optarg); #else fprintf(stderr, "--rtmark support was missing when " "this binary was compiled.\n"); exit(2); #endif } else if (option_index == 16) { /* --nohostroute */ nohostroute = 1; } break; case '?': /* unrecognised option */ /* fall through */ default: usage(argv[0]); } if (c == -1) break; /* no more options for pptp */ } /* 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); } tty_name = ttyname(tty_fd); snprintf(buf, sizeof(buf), "pptp: GRE-to-PPP gateway on %s", tty_name ? tty_name : "(null)"); #ifdef PR_SET_NAME rc = prctl(PR_SET_NAME, "pptpgw", 0, 0, 0); if (rc != 0) perror("prctl"); #else inststr(argc, argv, envp, buf); #endif 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. */ union { struct sockaddr a; struct sockaddr_un u; } 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.u, inetaddr, localbind); for (i = 0; i < NUM_TRIES; i++) { if (connect(fd, &where.a, sizeof(where)) < 0) { /* couldn't connect. We'll have to launch this guy. */ unlink (where.u.sun_path); /* FIXME: potential race condition */ /* 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 (WEXITSTATUS(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 __attribute__ ((unused)), 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]); #ifdef PR_SET_NAME int rc; rc = prctl(PR_SET_NAME, "pptpcm", 0, 0, 0); if (rc != 0) perror("prctl"); #else inststr(argc, argv, envp, buf); #endif 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. */ char str_pppd[] = PPPD_BINARY; char str_direct[] __attribute__ ((unused)) = "-direct"; char str_38400[] = "38400"; int i = 0, j; new_argv[i++] = str_pppd; #ifdef USER_PPP new_argv[i++] = str_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++] = str_38400; #endif for (j = 0; j < argc; j++) new_argv[i++] = argv[j]; new_argv[i] = NULL; execvp(new_argv[0], new_argv); } pptp-1.8.0/ChangeLog0000644000175000017500000010620212231702206013231 0ustar jamesjamesWed Oct 23 19:04:57 2013 James Cameron * pptp-1.8.0: released. Thu Aug 30 13:45:26 2012 Paul Howarth * options.pptp: fix typo in 'Encryption' comment, add notes and references regarding recent chapcrack exploit, note that the ppp_mppe kernel module will not load into the kernel if it's booted in FIPS mode (http://bugzilla.redhat.com/845112), and fix broken link to Jan Dubiec's ppp_mppe_mppc code. Wed Nov 30 09:02:18 2011 Paul Howarth * Makefile (config.h): fix unexpected build failure with a highly-parallel build (-j16). Thu Mar 3 12:24:15 2011 David Lamparter * pptp.c, pptp_callmgr.c, pptp.8: add -nohostroute option to disable adding a host route for the pptp server to the routing table. Also add some documentation while at it. Mon Feb 21 15:01:14 2011 David Lamparter * pptp.c, pptp_callmgr.c, pptp_gre.c, pptp.8: add --rtmark option for specifying the Linux policy routing / netfilter mark. Thu Sep 30 16:16:58 2010 Paul Howarth * pptp_ctrl.c: we could maintain a separate vector of peer call IDs and use that when we get a call-disconnect-notify packet to find our call ID and close that call, but as call-disconnect-notify packets are relatively rare, I've tried a slower but simpler approach of doing a linear search through the existing vector to look for the peer's call ID. Tue Jun 15 15:02:28 2010 James Cameron * pptp.c (open_callmgr): fix usage of status returned by waitpid; it must be wrapped by WEXITSTATUS to shift bits as required. Tue Jun 15 15:00:40 2010 James Cameron * pptp_ctrl.c (pptp_conn_is_dead): immediately destroying the connection and freeing the structure has led to segmentation faults on more recent heap implementations, since we use the structure after it has been freed. Defer the free of the structure until after all uses of it have ceased, by adding a connection state for dead and terminating the main loop once it is detected. Fri Jun 4 10:54:04 2010 Jan Just Keijser * pptp_ctrl.c: check for failure return by pptp_send_ctrl_packet and avoid using freed struct conn. Tue Nov 10 15:39:33 2009 Charles Shen * pptp_ctrl.c (ctrlp_disp): add call ID of outgoing call so that Call-Disconnect-Notify from peer causes correct disconnection sequence. Thu Jun 25 11:39:24 2009 James Cameron * AUTHORS: maintainer mail address change, james.cameron@hp.com is no longer valid. Mon Jun 1 14:43:00 2009 Paul Howarth * pptpsetup: only check for MPPE support in kernel and pppd if an encrypted tunnel is being created. Wed Mar 25 13:38:00 2009 Paul Howarth * pptpsetup: retain permissions on chap-secrets file when deleting tunnels (http://bugzilla.redhat.com/492090). Thu Jul 24 15:51:30 2008 Paul Howarth * routing.c, pptp_compat.c: compilation fixes for old distributions. Thu Jul 24 15:28:32 2008 Ilya Voronin * routing.c, Makefile: fixe use of /bin/ip and all compiler warnings on Solaris. Thu May 22 09:44:19 2008 James Cameron * routing.c: add config.h and use IP_BINARY. * Makefile (IP): add pointer to IP binary, store it in config.h, and add dependencies to support parallel make and development. Wed May 14 15:59:17 2008 James Cameron * pptp-1.7.2 released. Fri Jan 11 13:20:18 2008 Ilya Voronin * ppp_fcs.h, pptp.c, pptp_ctrl.h, pptp_gre.h, pptp_msg.h: port to Solaris 10/11. Wed Nov 21 14:29:46 2007 Leo Savernik * pptp_ctrl.c (pptp_fd_set): fix compile with an ANSI C89-compliant compiler. Tue Aug 28 10:17:36 2007 James Cameron * README, pptp.c: assign copyright to Free Software Foundation, and make license explicit. Signed-off-by: "C. Scott Ananian" Wed Apr 4 16:30:24 2007 James Cameron * pptp.8, pptp.c: add --test-type and --test-rate options. * pptp_gre.c: use alternate write(2) function for sending GRE packets. * test.c: implement reordering tests to assist with pptpd testing. These tests reorder the stream to simulate real-world examples. Fri Dec 15 02:02:08 2006 Michael Adda * pptp_gre.c: when we fail to write due to a transient error simply ignore it (treat it as a drop). Thu Oct 12 13:52:46 2006 James Cameron * pptp_gre.c (pptp_gre_copy): select(2) may return error, and the code was checking the read file descriptors without checking if they are valid. Thu Aug 17 14:36:18 2006 James Cameron * Makefile: add pptpsetup man page using pod2man. Wed Aug 2 16:21:08 2006 James Cameron * routing.c, routing.h, pptp_callmgr.c (callmgr_main): add route to PPTP server. Experimental feature. Note that this has a side-effect of leaving a route to the server in place after the tunnel has terminated. Wed Aug 2 16:19:06 2006 James Cameron * pptp.c: fix a few compilation warnings. Wed Aug 2 16:02:23 2006 James Cameron * pptpsetup: merge updates from Nelson Ferraz as of 24th April. * Makefile (dist): include pptpsetup in kit. Thu Apr 20 08:52:45 2006 James Cameron * Makefile (dist): remove Reference documentation as the license is non-free. The documentation is available from other sources. Thu Apr 20 08:49:01 2006 James Cameron * pptp.8: merge Debian contribution in 1.7.0-2 by Ola Lundqvist. Mon Apr 3 15:28:37 2006 James Cameron * pptpsetup: add script contributed by Nelson Ferraz. Mon Mar 27 10:09:20 2006 James Cameron * options.pptp: add refuse-pap to default options, along with a comment that a server may need to use PAP or CHAP if it is not using MPPE. Mon Feb 13 14:01:34 2006 James Cameron * pptp-1.7.1 released. Fri Feb 10 10:59:31 2006 James Cameron * pptp.c: use prctl(2) to set process name for gateway process so that killall(1) of pptp will affect control connection call manager only. Mon Aug 29 15:42:03 2005 James Cameron * pptp.c: add --version feature. Mon Aug 22 10:46:38 2005 James Cameron * util.c (sigpipe_assign): remove superfluous sigset variable and calls; they served no purpose. Reported by: Pavol Gono. Sat Aug 20 23:14:25 2005 James Cameron * options.pptp: default to not require MPPE, per Red Hat Bugzilla #166394. Thu Aug 11 10:46:32 2005 James Cameron * PROTOCOL-SECURITY: add write-up regarding protocol security risks. * Makefile (dist): add PROTOCOL-SECURITY write-up. Wed Jul 27 20:49:30 2005 James Cameron * pptp-1.7.0 released. Mon Jul 11 13:17:37 2005 James Cameron * pptp_gre.c (decaps_gre): silently discard packets that are not for this call. Reported by: Alan Jenkins. Thu Mar 31 17:41:17 2005 James Cameron * pptp_ctrl.c (pptp_dispatch): handle signals first, since there's a possibility of premature return from the function. * pptp_callmgr.c (callmgr_main): terminate faster when peer closes control connection. Thu Mar 10 11:07:52 2005 James Cameron * pptp_ctrl.c (pptp_handle_timer): when we close connection due to loss of echo replies, say so in the log. Reported by: Jean Wolter. * pptp_ctrl.c: fix signal deadlock on kernel 2.6.x Reported by: Jean Wolter. * util.c, util.h: adopt sigpipe implementation from pptpd. * pptp_ctrl.c (pptp_conn_open): use sigpipe implementation instead of trying I/O in signal handler (which causes deadlocks). * pptp_ctrl.c (pptp_fd_set): include the sigpipe in the file descriptor set. * pptp_ctrl.c (pptp_dispatch): detect queued signals via sigpipe. * pptp_ctrl.c (pptp_conn_destroy): close the sigpipe. Fri Feb 18 12:38:18 2005 James Cameron * pptp-1.6.0 released. Fri Feb 18 12:38:02 2005 James Cameron * Makefile (install): move options.pptp to this package from the RPM spec file. Tue Dec 14 08:56:07 2004 James Cameron * pptp_ctrl.c (ctrlp_disp): fix typo. From: Avi Kivity Tue Dec 7 09:43:00 2004 James Cameron * pptp_ctrl.c: add error propagation to the ctrlp_disp callchain, so that we don't double-free the connection on a stop control connection reply. From: Avi Kivity Wed Nov 10 09:49:48 2004 James Cameron * util.{c,h}: recent compilers spew a packetload of compilation warnings. From: Avi Kivity Tue Nov 9 12:30:57 2004 James Cameron * pptp.{8,c}, pptp_ctrl.c, pptp_options.h: add --idle-wait (time to wait before sending an echo request on the control connection) and --max-echo-wait (time to wait before giving up on lack of reply to an echo request). The latter is not yet implemented. Tue Nov 9 12:23:48 2004 James Cameron * pptp_callmgr.c, pptp_ctrl.{c,h}: pptp_dispatch and its subordinates insist on handling fatal errors by calling pptp_conn_destroy. unfortunately, as the comments say, callmgr_main uses the connection afterwards with the usual results. Added error propagation to the routines mentioned, allowing callmgr_main to have the honor of closing the connection. From: Avi Kivity Wed Oct 27 21:03:28 2004 James Cameron * pptp_callmgr.c (callmgr_main): pptp sometimes crashes in pptp_fd_set and leaves a core dump. Think this is due to a signal being caught and longjmp'ed to callmgr_main's shutdown label after we are out of that function, causing garbage local variables to be used. From: Avi Kivity Wed Jul 21 16:52:01 CEST 2004 Rein Klazes * pptp_ctrl.c (ctrlp_rep): Do not log sending of echo requests, preventing dead-locks observed with Linux 2.6 systems. The syslog call is not reentrant and must not be used within a signal handler. A better solution would probably be to get rid of the SIGALRM timer altogether. Wed Jul 21 19:00:59 2004 Peter Surda * pptp_callmgr.c (callmgr_main): prevent kill of init. Sat Jun 26 14:37:10 2004 James Cameron * pptp_gre.c (decaps_hdlc): portability fix, use IPPROTO_IP in place of SOL_IP in getsockopt(). From: Thomas Quinot Tue Jun 22 19:08:58 2004 James Cameron * Makefile, AUTHORS, rename package from pptp-linux to pptp. Tue Jun 22 18:08:27 2004 James Cameron * pptp-linux-1.5.0 released. Fri Jun 11 09:28:05 2004 Chris Wilson * pptp.8, pptp_gre.c: make the statistics work properly when buffering is disabled. Fix the issue with log messages claiming buffering when no buffering is being done. Thu Jun 10 16:58:53 2004 James Cameron * pptp.c (main): remove the sleep(3) on termination; it isn't really required; and causes the GRE-to-PPP gateway process to hang around after the connection has been terminated. * pptp.c (open_callmgr): call manager was inheriting the GRE socket, so close it before launching the callmgr, a regression introduced 18th July 2002, in the patch to bind the GRE socket earlier. Thu Jun 10 08:34:17 CEST 2004 Rein Klazes * pptp_callmgr.c: fix a case when the call manager does not shutdown properly, a regression introduced by the changes on 2003 Oct 22 and 23. Wed Jun 9 10:08:02 2004 Chris Wilson * pptp.8, pptp.c, pptp_gre.c, pptp_gre.h: add --nobuffer option to eliminate all buffering of packets, a "pptp quake patch". Wed Jun 9 09:37:06 2004 Paul Howarth * inststr.c: fix non-setting of the command line. Tue Jun 8 21:25:27 2004 James Cameron * pptp-linux-1.5.0-rc1 released. Sat Jun 5 22:44:50 2004 James Cameron * pptp_ctrl.c (pptp_read_some): fix for CPU loop after pppd killed with -9, if read() returns zero, it is because the control connection has closed, so destroy the connection. Wed Mar 24 08:45:12 2004 Mark-Andre Hopf * pptp.c: fix compile for ARM architecture. Mon Mar 8 11:04:00 2004 Chris Wilson * pptp.8: added documentation for command-line options where missing. Updated to reflect the use of getopt. Tue Mar 2 09:53:53 2004 Peter McCurdy * pptp.c (main, do_nothing): do not hang when a connection is refused. When the controlling process (pptp.c) paused while waiting for the child to send SIGUSR1, if the child died then the controlling process wouldn't ever wake up. Now if the child dies, SIGCHLD gets handled and the controlling process quits. Tue Feb 10 20:35:18 2004 James Cameron * pptp_gre.c (decaps_hdlc): temporarily add code that captures additional detail if EMSGSIZE is returned by read(). Fri Jan 2 10:05:17 2004 James Cameron * pptp-linux-1.4.0 released. Mon Dec 1 11:58:24 2003 James Cameron * pptp.c (main): remove arguments debugging printf. Wed Nov 26 12:22:00 2003 Chris Wilson * pptp.c: fixed argument handling so that hostname can be supplied anywhere on the command line, not just at the start. pppd options starting with "-" but before "--" are no longer supported. * pptp.c: added some spacing to improve readability, removed pointless "Step X" comments. * pptp.c: fixed usage message: there should not be a "pppd" in the command line. Mon Nov 10 15:39:41 2003 James Cameron * pptp-linux-1.4.0-rc1 released. Thu Oct 23 12:48:54 2003 James Cameron * pptp_callmgr.c (callmgr_main): if connection fails, pptp enters a CPU loop calling select() with no file descriptors set, and being given EBADF. Introduced by yesterday's modifications. Correct code to detect this situation and break the main loop. Wed Oct 22 13:02:04 2003 James Cameron * pptp_ctrl.c (pptp_call_open): add an assertion to prevent a call open attempt while the control connection is not established. * pptp_callmgr.c (callmgr_main): avoid accepting a UNIX socket connection and therefore calling pptp_call_open() if the control connection has not yet been established. * pptp_ctrl.c (pptp_conn_established): add function for pptp_callmgr.c to use to determine if the control connection has been established. TODO: if a connection reply is not received, what happens? Reported by: John BouAntoun Mon Sep 8 10:33:41 2003 James Cameron * pptp.c: fix for compile on OpenBSD. From: Waldemar Brodkorb Mon Aug 18 12:12:00 2003 Chris Wilson * pptp.c pptp_gre.c util.h: add log level control, to increase or reduce verbosity of log messages, for debugging and for people who have lossy connections. Thu Aug 7 12:20:09 2003 James Cameron * pptp_gre.c (decaps_gre): fix reporting of packet loss. From: Chris Wilson Wed Jun 25 12:59:28 2003 Rein Klazes * pptp_callmgr.c: Wait for the replies on our Call-Clear-Request's and Stop-Control-Connection-Request's. * pptp_ctrl.c: small tweak in a message about non existant call: report the received call ID's. Sun Jun 22 19:08:14 2003 Rein Klazes * pptp_ctrl.c: Log the buffering and sending of ALL control messages (except Echo messages and Replies of course). Change the way the sending of these messages is done. The original way was to first put them into a buffer ( in pptp_send_ctrl_packet()) and at some later write the buffered bytes to the socket ( in pptp_write_some()). Now pptp_send_ctrl_packet first attempts to write the packet directly. Only it the write() does not write all of the bytes, the remaining ones are buffered. This should help to track bugs in this area (like one sending two Start-Control-Request's). Thu Jun 19 09:09:53 2003 Rein Klazes * pptp_ctrl.c: Improve logging of received control packets: Move duplicated code to report on Result codes and General errors to a separate function; Verbosely report error codes embedded in start-control-connection replies; Translated some French comment; Log when an unexpected Outgoing Call Reply is received; Log the receipt of ALL control messages (except in case of echo request/reply packets of which only the first 10 are logged); Shorten the name of the function "pptp_dispatch_ctrl_packet" to "ctrlp_disp", 25 characters is just too much in the log files. Thu Jun 19 10:11:26 2003 Jan Pieter * Makefile (uninstall): include uninstall target, and a minor fix to dist. Wed Jun 18 12:19:09 2003 Rein Klazes * pptp_gre.c: Instead of logging the (a)synchronous mode of ppp, only issue a warning when it conflicts with the mode of pptp. Comparing two sequence numbers for(in)equality is safe even when a wrap-around has occurred. This contrasts with comparing for smaller/bigger. Remove a few unneeded tests for wrap-around. Tue Jun 17 19:40:41 2003 Rein Klazes * dirutil.c, ppp_fcs.c, pptp.c, pptp_gre.c, util.c, vector_test.c, * pptp_ctrl.c, pptp_callmgr.c, vector.c : reformat code with standard 4 spaced indents, uniform function headings and some general tidying up. Patches have been separated in "diff -w" invariant patches that should be safe and others that may be not so safe. Wed Jun 11 14:06:21 2003 Rein Klazes * pptp_gre.c: When a timeout is specified in the select call make it always non-zero. Making this call block makes it likely that pppd will run before the select returns. This results in a big reduction in transmitted ack-only packets (number down from 40% to 0.8% of received packets on my system). Tue Jun 11 18:42:00 2003 James Cameron * pptp-linux-1.3.1 released. Tue Jun 10 13:53:00 2003 Chris Wilson * pptp_callmgr.c: fixed a bug with call manager socket naming, introduced since 1.2.0, which caused confusing problems when trying to open more than one tunnel from the same machine. Tue Jun 10 18:43:34 2003 James Cameron * pptp-linux-1.3.0 released. Tue Jun 3 19:16:52 2003 James Cameron * pptp.8, pptp.c: change SIGHUP to SIGUSR1 for dumping stats. Tue May 20 13:20:00 2003 Chris Wilson * pptp.c: rewrote command-line usage information, to increase clarity and usefulness, and to describe various command-line options which have been added recently. Fri May 23 20:52:05 2003 Rein Klazes * pptp_ctrl.c: increase the verbosity of the log message at the receipt of a Call Disconnect Notification. Mon May 12 16:56:14 2003 James Cameron * Makefile: don't install the manpage with execute permission, swap LDFLAGS and LIBS so that one can say 'make LDFLAGS=-s' to create a stripped versions of the executables, introduce the optimization flag as a make variable, so that one can say 'make DEBUG= OPTIMIZE=-O2 LDFLAGS=-s'. From: Peter Breitenlohner Tue Apr 29 19:13:33 2003 James Cameron * Makefile (dist): remove CVS directory from distribution. Reported by: Ola Lundqvist Tue Apr 15 10:28:00 2003 Chris Wilson * pptp.c, pptp_gre.c, pptp_gre.h: Added GRE statistics counters and RTT calculation, which can be dumped to the syslog by sending a SIGHUP to the GRE-to-PPP gateway process. Mon Apr 14 11:57:00 2003 Chris Wilson * pptp_gre.c: Fixed one case where an ACK could be immediately followed by a data packet, they should be combined into a single packet. Sat Mar 8 2003 15:19:12 2003 Rein Klazes * pptp_gre.c, pqueue.c: Actually copy the packet into a new entry in the packet queue, fixing "unknown protocol" error messages; Change the program logic making it obvious that there is not a memory leak; Restore the "buffering out-of-order packet" log messages, so we have a chance to notice any more side effects. Mon Feb 17 09:18:30 2003 James Cameron * pptp_callmgr.c, pptp.c, Makefile: compile call manager from Makefile rather than include from pptp.c. From: Jan Pieter Sat Feb 15 21:32:42 2003 James Cameron * pptp_ctrl.c, pptp_msg.h: move code out of .h file and into .c file. From: Jan Pieter Sat Feb 15 17:34:38 2003 James Cameron * pptp.c: add include fixes for Apple MacOS X as contributed by an anonymous donor. Sat Feb 15 14:59:20 2003 James Cameron * pptp.c, pptp_callmgr.c, pptp_gre.c: add localbind option to support multiple clients from separate alias IP addresses. From: Yury Tarasievich, with contributions by Ed Marcotte. Fri Feb 14 10:11:27 2003 James Cameron * pptp-linux-1.2.0 released. Fri Feb 14 16:08:26 CET 2003 Rein Klazes * pptp_ctrl.c, pptp_msg.h: tweak the outgoing call reply messages once more. Print the error text that comes with the result code. * pptp.c: close all unused file descriptors belonging to the pty. * pptp_gre.c: Convert received acknowledgement numbers from network to host order. Mon Jan 20 11:46 2003 Chris Wilson * pqueue.c, pqueue.h: changed "expires" field of pqueue entry to a struct timeval for microsecond accuracy (in theory =) * pptp_gre.c: use queue head expiry time as the upper bound on how long we block waiting for data from the network or pppd * pptp.c: allow setting of packet timeout with sub-second accuracy, print error message to stderr and exit if timeout out of range Mon Jan 13 10:28 2003 Chris Wilson * pqueue.c, pqueue.h: added freelist support for packet queue, From: Kai Poitschke . Should help to prevent memory fragmentation and perhaps improve performance a little. * pqueue.c: wrap some log() statements with DEBUG_CMD, should improve performance (thanks to Kai Poitschke) * pptpd.c: bugfix for --log-string option: make a copy of the string with strdup, because optarg will be destroyed Wed Jan 15 14:16:27 2003 James Cameron * AUTHORS, DEVELOPERS, NEWS, README, TODO, USING: add or move CVS header to tail. * DEVELOPERS: change IRC server name to new alias. * AUTHORS: change a few addresses. * INSTALL: rewrite. * README, USING: review and adjust, minor changes. * Makefile (install): add MANDIR and man page. Thu Jan 2 11:28:41 2003 James Cameron * pptp_gre.c: fix response to dropped packets. From: Rein Klazes. Thu Jan 2 09:11:33 2003 James Cameron * pptp.8: the IP address should be before the option. From: Rein Klazes Mon Dec 30 15:57:48 2002 James Cameron * Makefile (install): add install target. Mon Dec 9 08:52:56 2002 James Cameron * pptp_callmgr.c, pptp.c: close stderr after becoming daemon, otherwise ssh sessions, CGI scripts, or other programs that start pptp don't exit properly; they are held up until the pptp processes terminate and close stderr. Thu Nov 21 08:41:39 2002 James Cameron * pptp_gre.c: log return value from the read of the GRE socket as a signed number as well. Wed Nov 20 11:21:48 CET 2002 Rein Klazes * pptp_gre.c: log return value from the read of the pty as a signed number. * pptp_ctrl.c: change the log message to clarify that error codes in a outgoing call reply come from the server, not the client. Wed Nov 20 16:07:30 2002 James Cameron * Makefile (dist): adjust distribution target to include new files since prior use. Wed Nov 20 15:17:12 2002 James Cameron * pptp_gre.c: hid many packet reordering log calls in an ifdef, added a hint as to cause of EIO on read of the pty. Fri Oct 11 15:44 BST 2002 Chris Wilson * pptp.c util.c util.h: added "--logstring" option to help identify connections in syslog output where multiple connections are made from the same host. Wed Oct 02 10:31 BST 2002 Chris Wilson * pptp_gre.c pqueue.c: changed some "log" statements to "warn" to reflect the severity of the condition, allowing much better filtering * util.c: changed _warn to log at WARNING, and _fatal at CRIT level * pptp_gre.c: disabled logging of individual accepted packets * pptp_gre.c: removed a potential NULL pointer dereference crash * pptp_gre.c: fixed the select-timeout check for packets in the queue * pqueue.h: increased window size to 300 following testing * pptp.c: added command-line parameter "--timeout" to set the lost packet timeout Fri Aug 30 09:55:05 CEST 2002 Rein Klazes pptp_gre.c: Try to send more ACK's piggy backed on data packets. Previously if there were any outstanding ACK's to be sent, the program used a non-blocking select (timeout zero) to see if any data packets are available. In most cases there will be none, since the time passed since the last read is too short and an ACK without data will be sent. This change allows one outstanding ACK, for at most 0.5 second, multiple outstanding ACK's are treated as before. Tests show that this gives a big reduction in the number of sent packets. Fri Aug 30 09:15:35 CEST 2002 Rein Klazes * pptp_gre.c: Sequence numbers of sent gre packets should start with 1. Mon Aug 26 10:56:42 CEST 2002 Rein Klazes * pptp.c pptp_gre.c pptp_gre.h: added "--sync" option to work in combination with the pppd sync option. In synchronous mode checksum calculations and (un-)escaping of control characters become unnecessary. This results in big CPU usage reduction. Mon Aug 26 08:53:45 CEST 2002 Rein Klazes * pptp.c: fix bug in command line options parsing (misplaced break in switch statement). Wed Aug 21 10:57:01 2002 James Cameron * pptp.c: add handler for SIGCHLD. From: Peter Surda Thu Aug 15 09:30:00 2002 Chris Wilson * pqueue.h: increased window size following James' tests * pptp_gre.c: check for errors while dequeueing packets Wed Aug 14 20:02:39 2002 James Cameron * pptp.c, pptp_gre.c, pqueue.c: packet re-ordering bugfixes following distributed testing: - Moved daemon() call to run on GRE gateway process only, and not if running as pppd pty - Make select() timeout after 1 second if there is data in the queue, to prevent the queue from having to wait forever - Added log messages for accepting individual packets (noisy!) and for timeouts on missing packets - Fixed a bug with the packet queue (append to tail was broken) - Removed unused code from pqueue.c From: chris@netservers.co.uk Wed Aug 14 11:14:05 2002 James Cameron * pqueue.c, pqueue.h, pptp_gre.c: major changes to support packet re-ordering. Queueing Packets are added to the queue by decaps_gre if their sequence number is higher than expected, but within the window. The default window is defined as 30 packets. Packets which are below the window (older than the most recent packet read) or above the window (too far ahead) are discarded, to protect against denial-of-service attacks. Dequeueing The new function dequeue_gre retrieves packets from the head of the queue which are: 1. Next in sequence (unwrapped or wrapped) 2. Older than five seconds (assuming that the intermediate packets have been lost by the network). The function will continue to read packets from the head of the queue until it finds one which doesn't match these criteria, and then stop. Limitations There are some limitations with this patch: - The receive window is hardcoded at 30 packets. I couldn't see where to get the negotiated and/or current window size from. - The timeout is hardcoded at 5 seconds. A packet which was received and queued within the window, but which should have been preceded by other packets which never appeared, will be accepted anyway after this time (increasing the sequence number to its own). - There may be memory leaks or other bugs in the reordering code. * pqueue.c, pqueue.h, Makefile (PPTP_OBJS, PPTP_DEPS): add two new files to the pptp executable. pqueue.c implements the packet queue used by the reordering code, and pqueue.h describes its public interface. The queue is implemented as a linked list. This is required for reordering. * pptp.c: Add a new command-line option, --debug. Prevents pptp from going into the background. Change to call the daemon(3) function to change the current directory and close the standard file descriptors. This prevents a shell from hanging open if pptp is started remotely. * Makefile (CFLAGS): reduce the optimisation level (gcc's -O flag) to zero (none), to make debugging easier. * pptp.c (get_ip_address): avoid reporting h_errno value. From: chris@netservers.co.uk Thu Jul 18 12:26:25 2002 James Cameron * pptp_gre.h, pptp_gre.c, pptp.c: bind the GRE socket early, by calling the a function pptp_gre_bind. Also changed prototype of pptp_gre_copy. Fixes ICMP Unreachable bug: <1026868263.2855.67.camel@jander> 16th July 2002. From: chris@netservers.co.uk Thu May 30 18:28:02 2002 James Cameron * pptp_ctrl.c (pptp_call_open): do translation to network byte order after limit checking of phone number. From: staelin@hpl.hp.com 2002-05-13 08:14:40 Muli Ben-Yehuda * TODO: remove 'remove setjmp/longjmp' TODO item. * pptp.c: change comment re volatile qualifiers. * pptp_callmgr.c: remove unused function 'conn_callback' and change comment re volatile qualifiers. Thu Apr 4 09:34:10 2002 James Cameron * pptp_ctrl.c: correct spelling error. From: Mary.Deck@COMPAQ.com 2002-03-30 13:13:52 mulix * USING: change URL for bezeq adsl howto. * pptp.c: (get_ip_address): if the user runs 'pptp --quirks ...' instead of 'pptp hostname', we'll get here and then give a verbose error message. Mon Mar 11 10:21:00 2002 mulix * Makefile (all): make config.h before making $(PPTP_BIN). * Makefile (config.h): truncate the file if it exists before inputing to it - '>' instead of '>>' Mon Mar 11 12:48:16 2002 James Cameron * DEVELOPERS: add mailing lists. * Makefile (CFLAGS): remove PPPD_BINARY and PPTP_LINUX_VERSION in favour of a config.h file. * Makefile (config.h): create config.h from Makefile variables * Makefile (PPTP_DEPS): add config.h * pptp.c: include config.h * version.c: include config.h * util.c (PROGRAM_NAME): no longer used by two programs, change PROGRAM_NAME to default to pptp. * Makefile (CFLAGS): remove -DPROGRAM_NAME Fri Mar 8 11:56:00 2002 mulix * TODO: remove notes about compiler warnings, as all compiler warnings are now gone. * pptp.c (main): add volatile qualifier to some variables to silence gcc warnings 'variable might be clobbered by longjmp or vfork'. add note explaining why volatile and that it should be removed when the longjmp is removed. * pptp_callmgr.c (main): likewise. * inststr.c (inststr): break up "ptr += strlen(++ptr)" which is undefined behaviour into two expressions. * pptp.c (main): initialize callmgr_sock to -1 since it might be used uninitialized otherwise. * pptp_ctrl.c (pptp_dispatch_ctrl_packet): #ifdef 0 two unused variables referring to the current packet, which should not be simply erased, as we might want to use them in the future. * util.c: add missing #include. Fri Mar 8 21:11:17 2002 James Cameron * DEVELOPERS: new file. Fri Mar 8 10:12:28 2002 James Cameron * NEWS: convert to newest first format to comply with GNU Coding Standards, The NEWS File. Fri Mar 8 09:01:22 2002 James Cameron * pptp_ctrl.c (pptp_make_packet): Cisco PIX is generating a non-complaint header with the reserved0 field not zero, causing the connection to stop after 60 seconds. From: Rein Klazes Fri Mar 8 08:56:30 2002 James Cameron * TODO: add compiler warnings note. * NEWS: propogate summary of ChangeLog. * AUTHORS: add names from mailing list contributions. From: Rein Klazes * Makefile: remove pptp_callmgr binary * debian/copyright: adjust pointer to current release. * debian/rules, Makefile: remove pptp_callmgr binary now that pptp forks and calls it without exec. Sat Mar 2 04:04:37 2002 James Cameron * README: adopt new mailing lists and point to project web site. * USING: include psuedo-tty activation instructions. * Makefile: increment version, avoid clobbering editor backup files on clean. Fri Mar 1 12:13:03 2002 James Cameron * pptp_gre.c: move #include higher up * pptp_gre.c, pptp_ctrl.c: change unsigned to unsigned int * pptp.c: what we need from pty.h is in libutil.h for FreeBSD and util.h for NetBSD (ideally this should be in autoconf) * pptp.c: synchronisation changes * orckit_quirks.c: #include From: rhialto@azenomei.knuffel.net Fri Nov 23 14:42:07 2001 James Cameron * USING: reformat, add version header. Tue Nov 20 11:01:10 2001 mulix * AUTHORS: add mulix. * USING: add paragraph on quirks support. * orckit_quirks.c: remove debugging call, rename functions and variables consistently. * pptp.c: (usage) remove debugging print. * pptp_ctrl.c: when calling quirks hooks, check their return values and warn if an error occurs. * pptp_quirks.c: orckit_atur3_start_ctrl_conn was renamed orckit_atur3_start_ctrl_conn_hook. From: mulix@actcom.co.il Tue Nov 20 17:01:10 2001 James Cameron * orckit_quirks.c, orckit_quirks.h: add quirks handling for orckit adsl modems. * pptp_quirks.c, pptp_quirks.h: add generic quirks handling. * Makefile (PPTP_DEPS, PPTP_OBJS, CALLMGR_OBJS, CALLMGR_DEPS): add quirks sources and objects. * pptp_ctrl.c: add pptp_set_link, add code to adjust packets depending on quirks. * pptp.c (usage, long_options, main): add --quirks command line option. From: mulix@actcom.co.il Tue Nov 20 16:45:35 2001 James Cameron * pptp_gre.c: enhance error message for bad FCS. pptp-1.8.0/version.c0000644000175000017500000000041512231702206013307 0ustar jamesjames/* version.c ..... keep track of package version number. * C. Scott Ananian * * $Id: version.c,v 1.3 2004/06/22 09:52:26 quozl Exp $ */ #include "config.h" const char * version = "pptp version " PPTP_LINUX_VERSION; pptp-1.8.0/inststr.h0000644000175000017500000000024012231702206013331 0ustar jamesjames/* inststr.h ..... change argv[0]. * * $Id: inststr.h,v 1.1 2000/12/23 08:19:51 scott Exp $ */ void inststr(int argc, char **argv, char **envp, char *src); pptp-1.8.0/ppp_fcs.c0000644000175000017500000001044012231702206013253 0ustar jamesjames/* Fast Frame Check Sequence (FCS) Implementation, for HDLC-like framing of * PPP. Adapted by C. Scott Ananian * from RFC1662: * * C.2. 16-bit FCS Computation Method * * The following code provides a table lookup computation for * calculating the Frame Check Sequence as data arrives at the * interface. This implementation is based on [7], [8], and [9]. * * [7] Perez, "Byte-wise CRC Calculations", IEEE Micro, June 1983. * * [8] Morse, G., "Calculating CRC's by Bits and Bytes", Byte, * September 1986. * * [9] LeVan, J., "A Fast CRC", Byte, November 1987. * * $Id: ppp_fcs.c,v 1.2 2003/06/17 17:25:47 reink Exp $ */ #include #include #include "ppp_fcs.h" #define ASSERT(x) assert(x) /* * u16 represents an unsigned 16-bit number. Adjust the typedef for * your hardware. */ typedef u_int16_t u16; /* * FCS lookup table as calculated by the table generator. */ static u16 fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; #ifndef PPPINITFCS16 #define PPPINITFCS16 0xffff /* Initial FCS value */ #endif #ifndef PPPGOODFCS16 #define PPPGOODFCS16 0xf0b8 /* Good final FCS value */ #endif /* * Calculate a new fcs given the current fcs and the new data. */ u16 pppfcs16(u16 fcs, void *_cp, int len) { register unsigned char *cp = (unsigned char *)_cp; /* don't worry about the efficiency of these asserts here. gcc will * recognise that the asserted expressions are constant and remove them. * Whether they are usefull is another question. */ ASSERT(sizeof (u16) == 2); ASSERT(((u16) -1) > 0); while (len--) fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff]; return (fcs); } #if 0 /* * How to use the fcs */ tryfcs16(cp, len) register unsigned char *cp; register int len; { u16 trialfcs; /* add on output */ trialfcs = pppfcs16( PPPINITFCS16, cp, len ); trialfcs ^= 0xffff; /* complement */ cp[len] = (trialfcs & 0x00ff); /* least significant byte first */ cp[len+1] = ((trialfcs >> 8) & 0x00ff); /* check on input */ trialfcs = pppfcs16( PPPINITFCS16, cp, len + 2 ); if ( trialfcs == PPPGOODFCS16 ) printf("Good FCS\n"); } #endif pptp-1.8.0/test.h0000644000175000017500000000021512231702206012604 0ustar jamesjamesstruct test_redirections { ssize_t (*write)(int fd, const void *buf, size_t count); }; struct test_redirections *test_redirections(void); pptp-1.8.0/Makefile0000644000175000017500000001033512231702206013120 0ustar jamesjames# $Id: Makefile,v 1.51 2011/11/29 22:05:07 quozl Exp $ VERSION=1.8.0 RELEASE= ################################################################# # CHANGE THIS LINE to point to the location of binaries PPPD = /usr/sbin/pppd # Solaris # PPPD = /usr/bin/pppd IP = /bin/ip ################################################################# BINDIR=$(DESTDIR)/usr/sbin MANDIR=$(DESTDIR)/usr/share/man/man8 PPPDIR=$(DESTDIR)/etc/ppp CC = gcc RM = rm -f OPTIMIZE= -O -Wuninitialized DEBUG = -g INCLUDE = CFLAGS = -Wall $(OPTIMIZE) $(DEBUG) $(INCLUDE) # Solaris # CFLAGS += -D_XPG4_2 -D__EXTENSIONS__ LIBS = -lutil # Solaris 10 # LIBS = -lnsl -lsocket -lresolv # Solaris Nevada build 14 or above # LIBS = -lnsl -lsocket LDFLAGS = PPTP_BIN = pptp PPTP_OBJS = pptp.o pptp_gre.o ppp_fcs.o \ pptp_ctrl.o dirutil.o vector.o \ inststr.o util.o version.o test.o \ pptp_quirks.o orckit_quirks.o pqueue.o pptp_callmgr.o routing.o \ pptp_compat.o PPTP_DEPS = pptp_callmgr.h pptp_gre.h ppp_fcs.h util.h test.h \ pptp_quirks.h orckit_quirks.h config.h pqueue.h routing.h all: config.h $(PPTP_BIN) pptpsetup.8 $(PPTP_BIN): $(PPTP_OBJS) $(PPTP_DEPS) $(CC) -o $(PPTP_BIN) $(PPTP_OBJS) $(LDFLAGS) $(LIBS) pptpsetup.8: pptpsetup pod2man $? > $@ config.h: ( \ echo "/* text added by Makefile target config.h */"; \ echo "#define PPTP_LINUX_VERSION \"$(VERSION)$(RELEASE)\""; \ echo "#define PPPD_BINARY \"$(PPPD)\""; \ echo "#define IP_BINARY \"$(IP)\"" \ ) > config.h vector_test: vector_test.o vector.o $(CC) -o vector_test vector_test.o vector.o clean: $(RM) *.o config.h clobber: clean $(RM) $(PPTP_BIN) vector_test distclean: clobber test: vector_test install: mkdir -p $(BINDIR) install -o root -m 555 pptp $(BINDIR) install -o root -m 555 pptpsetup $(BINDIR) mkdir -p $(MANDIR) install -m 644 pptp.8 $(MANDIR) install -m 644 pptpsetup.8 $(MANDIR) mkdir -p $(PPPDIR) install -m 644 options.pptp $(PPPDIR) uninstall: $(RM) $(BINDIR)/pptp $(MANDIR)/pptp.8 dist: clobber $(RM) pptp-$(VERSION)$(RELEASE).tar.gz $(RM) -r pptp-$(VERSION) mkdir pptp-$(VERSION) cp --recursive ChangeLog Makefile *.c *.h options.pptp pptp.8 \ pptpsetup Documentation AUTHORS COPYING INSTALL NEWS \ README DEVELOPERS TODO USING PROTOCOL-SECURITY \ pptp-$(VERSION)/ $(RM) -r pptp-$(VERSION)/CVS pptp-$(VERSION)/*/CVS tar czf pptp-$(VERSION)$(RELEASE).tar.gz pptp-$(VERSION) $(RM) -r pptp-$(VERSION) md5sum pptp-$(VERSION)$(RELEASE).tar.gz deb: chmod +x debian/rules fakeroot dpkg-buildpackage -us -uc mv ../pptp_$(VERSION)-0_i386.deb . WEB=~/public_html/external/mine/pptp/pptpconfig release: cp pptp_$(VERSION)-0_i386.deb $(WEB) cd $(WEB);make # The following include file dependencies were generated using # "makedepend -w0 *.c", then manually removing out of tree entries. # DO NOT DELETE dirutil.o: dirutil.h orckit_quirks.o: pptp_msg.h orckit_quirks.o: pptp_compat.h orckit_quirks.o: pptp_options.h orckit_quirks.o: pptp_ctrl.h orckit_quirks.o: util.h ppp_fcs.o: ppp_fcs.h ppp_fcs.o: pptp_compat.h pptp.o: config.h pptp.o: pptp_callmgr.h pptp.o: pptp_gre.h pptp.o: pptp_compat.h pptp.o: version.h pptp.o: inststr.h pptp.o: util.h pptp.o: pptp_quirks.h pptp.o: pptp_msg.h pptp.o: pptp_ctrl.h pptp.o: pqueue.h pptp.o: pptp_options.h pptp_callmgr.o: pptp_callmgr.h pptp_callmgr.o: pptp_ctrl.h pptp_callmgr.o: pptp_compat.h pptp_callmgr.o: pptp_msg.h pptp_callmgr.o: dirutil.h pptp_callmgr.o: vector.h pptp_callmgr.o: util.h pptp_callmgr.o: routing.h pptp_compat.o: pptp_compat.h pptp_compat.o: util.h pptp_ctrl.o: pptp_msg.h pptp_ctrl.o: pptp_compat.h pptp_ctrl.o: pptp_ctrl.h pptp_ctrl.o: pptp_options.h pptp_ctrl.o: vector.h pptp_ctrl.o: util.h pptp_ctrl.o: pptp_quirks.h pptp_gre.o: ppp_fcs.h pptp_gre.o: pptp_compat.h pptp_gre.o: pptp_msg.h pptp_gre.o: pptp_gre.h pptp_gre.o: util.h pptp_gre.o: pqueue.h pptp_gre.o: test.h pptp_quirks.o: orckit_quirks.h pptp_quirks.o: pptp_options.h pptp_quirks.o: pptp_ctrl.h pptp_quirks.o: pptp_compat.h pptp_quirks.o: pptp_msg.h pptp_quirks.o: pptp_quirks.h pqueue.o: util.h pqueue.o: pqueue.h routing.o: routing.h test.o: util.h test.o: test.h util.o: util.h vector.o: pptp_ctrl.h vector.o: pptp_compat.h vector.o: vector.h vector_test.o: vector.h vector_test.o: pptp_ctrl.h vector_test.o: pptp_compat.h version.o: config.h pptp-1.8.0/pptp_callmgr.h0000644000175000017500000000072212231702206014314 0ustar jamesjames/* pptp_callmgr.h ... Call manager for PPTP connections. * Handles TCP port 1723 protocol. * C. Scott Ananian * * $Id: pptp_callmgr.h,v 1.3 2003/02/17 00:22:17 quozl Exp $ */ #define PPTP_SOCKET_PREFIX "/var/run/pptp/" int callmgr_main(int argc, char**argv, char**envp); void callmgr_name_unixsock(struct sockaddr_un *where, struct in_addr inetaddr, struct in_addr localbind); pptp-1.8.0/pptp_gre.c0000644000175000017500000004711012231702206013445 0ustar jamesjames/* pptp_gre.c -- encapsulate PPP in PPTP-GRE. * Handle the IP Protocol 47 portion of PPTP. * C. Scott Ananian * * $Id: pptp_gre.c,v 1.49 2011/12/19 07:18:09 quozl Exp $ */ #include #include #include #include #include #include #include #include #include #if defined (__SVR4) && defined (__sun) #include #endif #include #include #include "ppp_fcs.h" #include "pptp_msg.h" #include "pptp_gre.h" #include "util.h" #include "pqueue.h" #include "test.h" /* globals from pptp.c */ extern struct in_addr localbind; extern int rtmark; #define PACKET_MAX 8196 /* test for a 32 bit counter overflow */ #define WRAPPED( curseq, lastseq) \ ((((curseq) & 0xffffff00) == 0) && \ (((lastseq) & 0xffffff00 ) == 0xffffff00)) static u_int32_t ack_sent, ack_recv; static u_int32_t seq_sent, seq_recv; static u_int16_t pptp_gre_call_id, pptp_gre_peer_call_id; gre_stats_t stats; typedef int (*callback_t)(int cl, void *pack, unsigned int len); /* decaps_hdlc gets all the packets possible with ONE blocking read */ /* returns <0 if read() call fails */ int decaps_hdlc(int fd, callback_t callback, int cl); int encaps_hdlc(int fd, void *pack, unsigned int len); int decaps_gre (int fd, callback_t callback, int cl); int encaps_gre (int fd, void *pack, unsigned int len); int dequeue_gre(callback_t callback, int cl); /* test redirection function pointers */ struct test_redirections *my; #if 1 #include void print_packet(int fd, void *pack, unsigned int len) { unsigned char *b = (unsigned char *)pack; unsigned int i,j; FILE *out = fdopen(fd, "w"); fprintf(out,"-- begin packet (%u) --\n", len); for (i = 0; i < len; i += 16) { for (j = 0; j < 8; j++) if (i + 2 * j + 1 < len) fprintf(out, "%02x%02x ", (unsigned int) b[i + 2 * j], (unsigned int) b[i + 2 * j + 1]); else if (i + 2 * j < len) fprintf(out, "%02x ", (unsigned int) b[i + 2 * j]); fprintf(out, "\n"); } fprintf(out, "-- end packet --\n"); fflush(out); } #endif /*** time_now_usecs ***********************************************************/ uint64_t time_now_usecs(void) { struct timeval tv; gettimeofday(&tv, NULL); return (tv.tv_sec * 1000000) + tv.tv_usec; } /*** Open IP protocol socket **************************************************/ int pptp_gre_bind(struct in_addr inetaddr) { union { struct sockaddr a; struct sockaddr_in i; } loc_addr, src_addr; int s = socket(AF_INET, SOCK_RAW, PPTP_PROTO); if (s < 0) { warn("socket: %s", strerror(errno)); return -1; } #ifdef SO_MARK if (rtmark) { if (setsockopt(s, SOL_SOCKET, SO_MARK, &rtmark, sizeof(rtmark))) { warn("setsockopt(SO_MARK): %s", strerror(errno)); close(s); return -1; } } #endif if (localbind.s_addr != INADDR_NONE) { bzero(&loc_addr, sizeof(loc_addr)); loc_addr.i.sin_family = AF_INET; loc_addr.i.sin_addr = localbind; if (bind(s, &loc_addr.a, sizeof(loc_addr.i)) != 0) { warn("bind: %s", strerror(errno)); close(s); return -1; } } src_addr.i.sin_family = AF_INET; src_addr.i.sin_addr = inetaddr; src_addr.i.sin_port = 0; if (connect(s, &src_addr.a, sizeof(src_addr.i)) < 0) { warn("connect: %s", strerror(errno)); close(s); return -1; } my = test_redirections(); return s; } /*** pptp_gre_copy ************************************************************/ void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id, int pty_fd, int gre_fd) { int max_fd; pptp_gre_call_id = call_id; pptp_gre_peer_call_id = peer_call_id; /* Pseudo-terminal already open. */ ack_sent = ack_recv = seq_sent = seq_recv = 0; /* weird select semantics */ max_fd = gre_fd; if (pty_fd > max_fd) max_fd = pty_fd; /* Dispatch loop */ for (;;) { /* until error happens on gre_fd or pty_fd */ struct timeval tv = {0, 0}; struct timeval *tvp; fd_set rfds; int retval; pqueue_t *head; int block_usecs = -1; /* wait forever */ /* watch terminal and socket for input */ FD_ZERO(&rfds); FD_SET(gre_fd, &rfds); FD_SET(pty_fd, &rfds); /* * if there are multiple pending ACKs, then do a minimal timeout; * else if there is a single pending ACK then timeout after 0,5 seconds; * else block until data is available. */ if (ack_sent != seq_recv) { if (ack_sent + 1 == seq_recv) /* u_int wrap-around safe */ block_usecs = 500000; else /* don't use zero, this will force a resceduling */ /* when calling select(), giving pppd a chance to */ /* run. */ block_usecs = 1; } /* otherwise block_usecs == -1, which means wait forever */ /* * If there is a packet in the queue, then don't wait longer than * the time remaining until it expires. */ head = pqueue_head(); if (head != NULL) { int expiry_time = pqueue_expiry_time(head); if (block_usecs == -1 || expiry_time < block_usecs) block_usecs = expiry_time; } if (block_usecs == -1) { tvp = NULL; } else { tvp = &tv; tv.tv_usec = block_usecs; tv.tv_sec = tv.tv_usec / 1000000; tv.tv_usec %= 1000000; } retval = select(max_fd + 1, &rfds, NULL, NULL, tvp); if (retval > 0 && FD_ISSET(pty_fd, &rfds)) { if (decaps_hdlc(pty_fd, encaps_gre, gre_fd) < 0) break; } else if (retval == 0 && ack_sent != seq_recv) { /* if outstanding ack */ /* send ack with no payload */ encaps_gre(gre_fd, NULL, 0); } if (retval > 0 && FD_ISSET(gre_fd, &rfds)) { if (decaps_gre (gre_fd, encaps_hdlc, pty_fd) < 0) break; } if (dequeue_gre (encaps_hdlc, pty_fd) < 0) break; } /* Close up when done. */ close(gre_fd); close(pty_fd); } #define HDLC_FLAG 0x7E #define HDLC_ESCAPE 0x7D #define HDLC_TRANSPARENCY 0x20 /* ONE blocking read per call; dispatches all packets possible */ /* returns 0 on success, or <0 on read failure */ int decaps_hdlc(int fd, int (*cb)(int cl, void *pack, unsigned int len), int cl) { unsigned char buffer[PACKET_MAX]; ssize_t start = 0, end; int status; static unsigned int len = 0, escape = 0; static unsigned char copy[PACKET_MAX]; static int checkedsync = 0; /* start is start of packet. end is end of buffer data */ /* this is the only blocking read we will allow */ if ((end = read (fd, buffer, sizeof(buffer))) <= 0) { int saved_errno = errno; warn("short read (%zd): %s", end, strerror(saved_errno)); switch (saved_errno) { case EMSGSIZE: { socklen_t optval, optlen = sizeof(optval); warn("transmitted GRE packet triggered an ICMP destination unreachable, fragmentation needed, or exceeds the MTU of the network interface"); #define IP_MTU 14 if(getsockopt(fd, IPPROTO_IP, IP_MTU, &optval, &optlen) < 0) warn("getsockopt: %s", strerror(errno)); warn("getsockopt: IP_MTU: %d\n", optval); return 0; } case EIO: warn("pppd may have shutdown, see pppd log"); break; } return -1; } /* warn if the sync options of ppp and pptp don't match */ if( !checkedsync) { checkedsync = 1; if( buffer[0] == HDLC_FLAG){ if( syncppp ) warn( "pptp --sync option is active, " "yet the ppp mode is asynchronous!\n"); } else if( !syncppp ) warn( "The ppp mode is synchronous, " "yet no pptp --sync option is specified!\n"); } /* in synchronous mode there are no hdlc control characters nor checksum * bytes. Find end of packet with the length information in the PPP packet */ if ( syncppp ){ while ( start + 8 < end) { len = ntoh16(*(short int *)(buffer + start + 6)) + 4; /* note: the buffer may contain an incomplete packet at the end * this packet will be read again at the next read() */ if ( start + len <= end) if ((status = cb (cl, buffer + start, len)) < 0) return status; /* error-check */ start += len; } return 0; } /* asynchronous mode */ while (start < end) { /* Copy to 'copy' and un-escape as we go. */ while (buffer[start] != HDLC_FLAG) { if ((escape == 0) && buffer[start] == HDLC_ESCAPE) { escape = HDLC_TRANSPARENCY; } else { if (len < PACKET_MAX) copy [len++] = buffer[start] ^ escape; escape = 0; } start++; if (start >= end) return 0; /* No more data, but the frame is not complete yet. */ } /* found flag. skip past it */ start++; /* check for over-short packets and silently discard, as per RFC1662 */ if ((len < 4) || (escape != 0)) { len = 0; escape = 0; continue; } /* check, then remove the 16-bit FCS checksum field */ if (pppfcs16 (PPPINITFCS16, copy, len) != PPPGOODFCS16) warn("Bad Frame Check Sequence during PPP to GRE decapsulation"); len -= sizeof(u_int16_t); /* so now we have a packet of length 'len' in 'copy' */ if ((status = cb (cl, copy, len)) < 0) return status; /* error-check */ /* Great! Let's do more! */ len = 0; escape = 0; } return 0; /* No more data to process. */ } /*** Make stripped packet into HDLC packet ************************************/ int encaps_hdlc(int fd, void *pack, unsigned int len) { unsigned char *source = (unsigned char *)pack; unsigned char dest[2 * PACKET_MAX + 2]; /* largest expansion possible */ unsigned int pos = 0, i; u_int16_t fcs; /* in synchronous mode there is little to do */ if ( syncppp ) return write(fd, source, len); /* asynchronous mode */ /* Compute the FCS */ fcs = pppfcs16(PPPINITFCS16, source, len) ^ 0xFFFF; /* start character */ dest[pos++] = HDLC_FLAG; /* escape the payload */ for (i = 0; i < len + 2; i++) { /* wacked out assignment to add FCS to end of source buffer */ unsigned char c = (i < len)?source[i]:(i == len)?(fcs & 0xFF):((fcs >> 8) & 0xFF); if (pos >= sizeof(dest)) break; /* truncate on overflow */ if ( (c < 0x20) || (c == HDLC_FLAG) || (c == HDLC_ESCAPE) ) { dest[pos++] = HDLC_ESCAPE; if (pos < sizeof(dest)) dest[pos++] = c ^ 0x20; } else dest[pos++] = c; } /* tack on the end-flag */ if (pos < sizeof(dest)) dest[pos++] = HDLC_FLAG; /* now write this packet */ return write(fd, dest, pos); } /*** decaps_gre ***************************************************************/ int decaps_gre (int fd, callback_t callback, int cl) { unsigned char buffer[PACKET_MAX + 64 /*ip header*/]; struct pptp_gre_header *header; int status, ip_len = 0; static int first = 1; unsigned int headersize; unsigned int payload_len; u_int32_t seq; if ((status = read (fd, buffer, sizeof(buffer))) <= 0) { warn("short read (%d): %s", status, strerror(errno)); stats.rx_errors++; return -1; } /* strip off IP header, if present */ if ((buffer[0] & 0xF0) == 0x40) ip_len = (buffer[0] & 0xF) * 4; header = (struct pptp_gre_header *)(buffer + ip_len); /* verify packet (else discard) */ if ( /* version should be 1 */ ((ntoh8(header->ver) & 0x7F) != PPTP_GRE_VER) || /* PPTP-GRE protocol for PPTP */ (ntoh16(header->protocol) != PPTP_GRE_PROTO)|| /* flag C should be clear */ PPTP_GRE_IS_C(ntoh8(header->flags)) || /* flag R should be clear */ PPTP_GRE_IS_R(ntoh8(header->flags)) || /* flag K should be set */ (!PPTP_GRE_IS_K(ntoh8(header->flags))) || /* routing and recursion ctrl = 0 */ ((ntoh8(header->flags)&0xF) != 0)) { /* if invalid, discard this packet */ warn("Discarding GRE: %X %X %X %X %X %X", ntoh8(header->ver)&0x7F, ntoh16(header->protocol), PPTP_GRE_IS_C(ntoh8(header->flags)), PPTP_GRE_IS_R(ntoh8(header->flags)), PPTP_GRE_IS_K(ntoh8(header->flags)), ntoh8(header->flags) & 0xF); stats.rx_invalid++; return 0; } /* silently discard packets not for this call */ if (ntoh16(header->call_id) != pptp_gre_call_id) return 0; /* test if acknowledgement present */ if (PPTP_GRE_IS_A(ntoh8(header->ver))) { u_int32_t ack = (PPTP_GRE_IS_S(ntoh8(header->flags)))? header->ack:header->seq; /* ack in different place if S = 0 */ ack = ntoh32( ack); if (ack > ack_recv) ack_recv = ack; /* also handle sequence number wrap-around */ if (WRAPPED(ack,ack_recv)) ack_recv = ack; if (ack_recv == stats.pt.seq) { int rtt = time_now_usecs() - stats.pt.time; stats.rtt = (stats.rtt + rtt) / 2; } } /* test if payload present */ if (!PPTP_GRE_IS_S(ntoh8(header->flags))) return 0; /* ack, but no payload */ headersize = sizeof(*header); payload_len = ntoh16(header->payload_len); seq = ntoh32(header->seq); /* no ack present? */ if (!PPTP_GRE_IS_A(ntoh8(header->ver))) headersize -= sizeof(header->ack); /* check for incomplete packet (length smaller than expected) */ if (status - headersize < payload_len) { warn("discarding truncated packet (expected %d, got %d bytes)", payload_len, status - headersize); stats.rx_truncated++; return 0; } /* check for expected sequence number */ if ( first || (seq == seq_recv + 1)) { /* wrap-around safe */ if ( log_level >= 2 ) log("accepting packet %d", seq); stats.rx_accepted++; first = 0; seq_recv = seq; return callback(cl, buffer + ip_len + headersize, payload_len); /* out of order, check if the number is too low and discard the packet. * (handle sequence number wrap-around, and try to do it right) */ } else if ( seq < seq_recv + 1 || WRAPPED(seq_recv, seq) ) { if ( log_level >= 1 ) log("discarding duplicate or old packet %d (expecting %d)", seq, seq_recv + 1); stats.rx_underwin++; /* sequence number too high, is it reasonably close? */ } else if ( seq < seq_recv + MISSING_WINDOW || WRAPPED(seq, seq_recv + MISSING_WINDOW) ) { stats.rx_buffered++; if ( log_level >= 1 ) log("%s packet %d (expecting %d, lost or reordered)", disable_buffer ? "accepting" : "buffering", seq, seq_recv+1); if ( disable_buffer ) { seq_recv = seq; stats.rx_lost += seq - seq_recv - 1; return callback(cl, buffer + ip_len + headersize, payload_len); } else { pqueue_add(seq, buffer + ip_len + headersize, payload_len); } /* no, packet must be discarded */ } else { if ( log_level >= 1 ) warn("discarding bogus packet %d (expecting %d)", seq, seq_recv + 1); stats.rx_overwin++; } return 0; } /*** dequeue_gre **************************************************************/ int dequeue_gre (callback_t callback, int cl) { pqueue_t *head; int status; /* process packets in the queue that either are expected or have * timed out. */ head = pqueue_head(); while ( head != NULL && ( (head->seq == seq_recv + 1) || /* wrap-around safe */ (pqueue_expiry_time(head) <= 0) ) ) { /* if it is timed out... */ if (head->seq != seq_recv + 1 ) { /* wrap-around safe */ stats.rx_lost += head->seq - seq_recv - 1; if (log_level >= 2) log("timeout waiting for %d packets", head->seq - seq_recv - 1); } if (log_level >= 2) log("accepting %d from queue", head->seq); seq_recv = head->seq; status = callback(cl, head->packet, head->packlen); pqueue_del(head); if (status < 0) return status; head = pqueue_head(); } return 0; } /*** encaps_gre ***************************************************************/ int encaps_gre (int fd, void *pack, unsigned int len) { union { struct pptp_gre_header header; unsigned char buffer[PACKET_MAX + sizeof(struct pptp_gre_header)]; } u; static u_int32_t seq = 1; /* first sequence number sent must be 1 */ unsigned int header_len; int rc; /* package this up in a GRE shell. */ u.header.flags = hton8 (PPTP_GRE_FLAG_K); u.header.ver = hton8 (PPTP_GRE_VER); u.header.protocol = hton16(PPTP_GRE_PROTO); u.header.payload_len = hton16(len); u.header.call_id = hton16(pptp_gre_peer_call_id); /* special case ACK with no payload */ if (pack == NULL) { if (ack_sent != seq_recv) { u.header.ver |= hton8(PPTP_GRE_FLAG_A); u.header.payload_len = hton16(0); /* ack is in odd place because S == 0 */ u.header.seq = hton32(seq_recv); ack_sent = seq_recv; rc = (*my->write)(fd, &u.header, sizeof(u.header) - sizeof(u.header.seq)); if (rc < 0) { if (errno == ENOBUFS) rc = 0; /* Simply ignore it */ stats.tx_failed++; } else if ((size_t)rc < sizeof(u.header) - sizeof(u.header.seq)) { stats.tx_short++; } else { stats.tx_acks++; } return rc; } else return 0; /* we don't need to send ACK */ } /* explicit brace to avoid ambiguous `else' warning */ /* send packet with payload */ u.header.flags |= hton8(PPTP_GRE_FLAG_S); u.header.seq = hton32(seq); if (ack_sent != seq_recv) { /* send ack with this message */ u.header.ver |= hton8(PPTP_GRE_FLAG_A); u.header.ack = hton32(seq_recv); ack_sent = seq_recv; header_len = sizeof(u.header); } else { /* don't send ack */ header_len = sizeof(u.header) - sizeof(u.header.ack); } if (header_len + len >= sizeof(u.buffer)) { stats.tx_oversize++; return 0; /* drop this, it's too big */ } /* copy payload into buffer */ memcpy(u.buffer + header_len, pack, len); /* record and increment sequence numbers */ seq_sent = seq; seq++; /* write this baby out to the net */ /* print_packet(2, u.buffer, header_len + len); */ rc = (*my->write)(fd, u.buffer, header_len + len); if (rc < 0) { if (errno == ENOBUFS) rc = 0; /* Simply ignore it */ stats.tx_failed++; } else if ((size_t)rc < header_len + len) { stats.tx_short++; } else { stats.tx_sent++; stats.pt.seq = seq_sent; stats.pt.time = time_now_usecs(); } return rc; } pptp-1.8.0/INSTALL0000644000175000017500000000241012231702206012504 0ustar jamesjamesInstallation Instructions - Brief 1. install pppd (with MPPE if you require it), 2. if pppd is not in /usr/sbin, edit Makefile, variable PPPD, 3. 'make' 4. 'make install' Installation Instructions - Detailed 1. install PPP, and make sure it is working. On most distributions, use the package called ppp or pppd. If your PPTP server requires MPPE, make sure the pppd program has been built with MPPE and MS-CHAP support. PPP from version 2.4.2 onwards has this support. PPP may require kernel support for MPPE, which may require patching your kernel. 2. verify that the pppd program is in the /usr/sbin/ directory. On some distributions, it is in /usr/bin, or somewhere else. If it isn't in the default directory, edit the Makefile, and change the PPPD variable to point at the pppd program. You may even want to run a separate pppd program with MPPE support. 3. compile Type 'make'. This should generate the 'pptp' executable. 4. install binaries Type 'make install' to have the program and the manual page installed. Further information http://pptpclient.sourceforge.net/ $Id: INSTALL,v 1.2 2003/01/15 05:29:20 quozl Exp $ pptp-1.8.0/dirutil.h0000644000175000017500000000107712231702206013310 0ustar jamesjames/* dirutil.h ... directory utilities. * C. Scott Ananian * * $Id: dirutil.h,v 1.1 2000/12/23 08:19:51 scott Exp $ */ /* Returned malloc'ed string representing basename */ char *basenamex(char *pathname); /* Return malloc'ed string representing directory name (no trailing slash) */ char *dirname(char *pathname); /* In-place modify a string to remove trailing slashes. Returns arg. */ char *stripslash(char *pathname); /* ensure dirname exists, creating it if necessary. */ int make_valid_path(char *dirname, mode_t mode); pptp-1.8.0/vector_test.c0000644000175000017500000000521412231702206014165 0ustar jamesjames/* vector_test.c .... Test the vector package. * C. Scott Ananian * * $Id: vector_test.c,v 1.2 2003/06/17 17:25:47 reink Exp $ */ #include #include #include "vector.h" #define MAX 25 void main(void) { int i, j, retval; VECTOR *v = vector_create(); assert(v != NULL); assert(vector_size(v)==0); for (i=0; i<=MAX; i++) { assert(!vector_contains(v, i)); assert(!vector_remove(v, i)); assert(!vector_search(v, i, (PPTP_CALL **)&j)); retval = vector_scan(v, i, MAX*2, &j); assert(retval); assert(j==i); } for (i=1; i<=MAX; i++) { retval = vector_insert(v, i, (PPTP_CALL *)i); assert(retval); assert(vector_size(v)==i); } for (i=1; i