diff -Nru2 --exclude CVS pptp-linux-1.1.0/AUTHORS src/AUTHORS --- pptp-linux-1.1.0/AUTHORS Fri Mar 8 00:23:37 2002 +++ src/AUTHORS Thu Jul 18 03:36:51 2002 @@ -15,2 +15,3 @@ Jeff Wiedemeier Yura Zotov +Chris Wilson diff -Nru2 --exclude CVS pptp-linux-1.1.0/ChangeLog src/ChangeLog --- pptp-linux-1.1.0/ChangeLog Mon Mar 11 08:36:52 2002 +++ src/ChangeLog Fri Aug 16 09:35:28 2002 @@ -1,2 +1,120 @@ +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 diff -Nru2 --exclude CVS pptp-linux-1.1.0/Makefile src/Makefile --- pptp-linux-1.1.0/Makefile Mon Mar 11 08:36:52 2002 +++ src/Makefile Wed Aug 14 09:00:48 2002 @@ -10,5 +10,5 @@ DEBUG = -g INCLUDE = -CFLAGS = -Wall -O1 $(DEBUG) $(INCLUDE) +CFLAGS = -Wall -O0 $(DEBUG) $(INCLUDE) LIBS = LDFLAGS = -lutil @@ -19,8 +19,8 @@ pptp_ctrl.o dirutil.o vector.o \ inststr.o util.o version.o \ - pptp_quirks.o orckit_quirks.o + pptp_quirks.o orckit_quirks.o pqueue.o PPTP_DEPS = pptp_callmgr.h pptp_gre.h ppp_fcs.h util.h \ - pptp_quirks.h orckit_quirks.h config.h + pptp_quirks.h orckit_quirks.h config.h pqueue.h all: config.h $(PPTP_BIN) diff -Nru2 --exclude CVS pptp-linux-1.1.0/NEWS src/NEWS --- pptp-linux-1.1.0/NEWS Thu Mar 7 23:13:27 2002 +++ src/NEWS Wed Aug 14 09:00:48 2002 @@ -1,2 +1,5 @@ +- 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: diff -Nru2 --exclude CVS pptp-linux-1.1.0/TODO src/TODO --- pptp-linux-1.1.0/TODO Mon Mar 11 01:33:03 2002 +++ src/TODO Mon May 13 06:37:46 2002 @@ -1,5 +1,7 @@ -10th March 2002 +1st May 2002 -- redesign to avoid use of setjmp/longjmp. +- log failure of write() to raw socket, as Ryan Murray + has encountered an EPERM situation that was not + being logged. 12th February 2002 diff -Nru2 --exclude CVS pptp-linux-1.1.0/USING src/USING --- pptp-linux-1.1.0/USING Fri Mar 1 16:55:57 2002 +++ src/USING Sun Mar 31 12:14:56 2002 @@ -1,3 +1,3 @@ -$Id: USING,v 1.3 2002/03/01 16:55:57 quozl Exp $ +$Id: USING,v 1.4 2002/03/31 11:14:56 mulix Exp $ pptp is started as a psuedo-tty child process using pppd's pty option: @@ -46,4 +46,4 @@ More information on Bezeq's ADSL service can be found at -http://www.pointer.co.il/~mulix/adsl-howto.txt and +http://vipe.technion.il/~mulix/adsl-howto.txt and http://damyen.technion.ac.il/~dani/adsl-howto.txt. diff -Nru2 --exclude CVS pptp-linux-1.1.0/debian/README.Reference src/debian/README.Reference --- pptp-linux-1.1.0/debian/README.Reference Sat Dec 23 08:32:15 2000 +++ src/debian/README.Reference Thu Apr 4 16:31:37 2002 @@ -16,4 +16,4 @@ Note: -The following RFCs are note included: 791, 793, 1661, 1662 +The following RFCs are not included: 791, 793, 1661, 1662 They can be found in package doc-rfc. diff -Nru2 --exclude CVS pptp-linux-1.1.0/debian/changelog src/debian/changelog --- pptp-linux-1.1.0/debian/changelog Fri Mar 22 04:09:14 2002 +++ src/debian/changelog Fri Mar 22 09:46:17 2002 @@ -1,7 +1,7 @@ -pptp-linux (1.1.0-1) frozen unstable; urgency=low +pptp-linux (1.1.0-1) unstable; urgency=low * New upstream release. - -- James Cameron Fri, 20 Mar 2002 11:30:55 +1100 + -- Thomas Quinot Fri, 20 Mar 2002 11:30:55 +1100 pptp-linux (1.0.3-2) frozen unstable; urgency=low diff -Nru2 --exclude CVS pptp-linux-1.1.0/pptp.c src/pptp.c --- pptp-linux-1.1.0/pptp.c Mon Mar 11 01:51:41 2002 +++ src/pptp.c Thu Aug 15 09:11:43 2002 @@ -3,5 +3,5 @@ * C. Scott Ananian * - * $Id: pptp.c,v 1.11 2002/03/11 01:51:41 quozl Exp $ + * $Id: pptp.c,v 1.16 2002/08/14 10:04:20 quozl Exp $ */ @@ -79,5 +79,5 @@ /* TODO: redesign to avoid longjmp/setjmp. Several variables here have a volatile qualifier to silence warnings from gcc < 3.0. - Remove the volatile qualifiers when longjmp/setjmp are removed. */ + Remove the volatile qualifiers if longjmp/setjmp are removed. */ int main(int argc, char **argv, char **envp) { @@ -85,5 +85,5 @@ volatile int callmgr_sock = -1; char ttydev[PATH_MAX]; - int pty_fd, tty_fd, rc; + int pty_fd, tty_fd, gre_fd, rc; volatile pid_t parent_pid, child_pid; u_int16_t call_id, peer_call_id; @@ -93,5 +93,6 @@ * '\0' */ char * volatile phonenr = NULL; - volatile int launchpppd = 1; + volatile int launchpppd = 1, debug = 0; + if (argc < 2) usage(argv[0]); @@ -109,4 +110,5 @@ {"nolaunchpppd", 0, 0, 0}, {"quirks", 1, 0, 0}, + {"debug", 0, 0, 0}, {0, 0, 0, 0} }; @@ -119,18 +121,21 @@ 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]); - } + 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 { /* other pptp options come here */ break; + } case '?': /* unrecognised option, treat it as the first pppd option */ /* fall through */ @@ -143,5 +148,15 @@ pppdargc = argc - optind; pppdargv = argv + optind; - + + /* Step 2a: 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."); + } + /* Step 3: Find an open pty/tty pair. */ if(launchpppd){ @@ -196,12 +211,17 @@ /* Step 5b: Send signal to wake up pppd task */ - if(launchpppd){ - kill(parent_pid, SIGUSR1); - sleep(2); + if (launchpppd){ + kill(parent_pid, SIGUSR1); + sleep(2); + /* be a good daemon and close our stdin/out/err fds */ + if (!debug && daemon(0, 0) != 0) { + perror("daemon"); + } } { char buf[128]; - snprintf(buf, sizeof(buf), "pptp: GRE-to-PPP gateway on %s", ttyname(tty_fd)); + snprintf(buf, sizeof(buf), "pptp: GRE-to-PPP gateway on %s", + ttyname(tty_fd)); inststr(argc,argv,envp, buf); } @@ -213,5 +233,5 @@ /* Step 6: Do GRE copy until close. */ - pptp_gre_copy(call_id, peer_call_id, pty_fd, inetaddr); + pptp_gre_copy(call_id, peer_call_id, pty_fd, gre_fd); shutdown: @@ -230,13 +250,13 @@ if (host==NULL) { if (h_errno == HOST_NOT_FOUND) - fatal("gethostbyname: HOST NOT FOUND"); + fatal("gethostbyname '%s': HOST NOT FOUND", name); else if (h_errno == NO_ADDRESS) - fatal("gethostbyname: NO IP ADDRESS"); + fatal("gethostbyname '%s': NO IP ADDRESS", name); else - fatal("gethostbyname: name server error"); + fatal("gethostbyname '%s': name server error", name); } if (host->h_addrtype != AF_INET) - fatal("Host has non-internet address"); + fatal("Host '%s' has non-internet address", name); memcpy(&retval.s_addr, host->h_addr, sizeof(retval.s_addr)); diff -Nru2 --exclude CVS pptp-linux-1.1.0/pptp_callmgr.c src/pptp_callmgr.c --- pptp-linux-1.1.0/pptp_callmgr.c Mon Mar 11 01:51:41 2002 +++ src/pptp_callmgr.c Mon May 13 06:37:46 2002 @@ -3,5 +3,5 @@ * C. Scott Ananian * - * $Id: pptp_callmgr.c,v 1.5 2002/03/11 01:51:41 quozl Exp $ + * $Id: pptp_callmgr.c,v 1.6 2002/05/13 05:37:46 mulix Exp $ */ #include @@ -52,18 +52,4 @@ }; -/* Connection callback */ -void conn_callback(PPTP_CONN *conn, enum conn_state state) { - - switch(state) { - case CONN_OPEN_FAIL: - case CONN_CLOSE_DONE: - /* get outta here */ - siglongjmp(env, 1); - break; - default: - log("Unhandled connection callback state [%d].", (int) state); - break; - } -} /* Call callback */ void call_callback(PPTP_CONN *conn, PPTP_CALL *call, enum call_state state) { @@ -108,5 +94,5 @@ /* NOTE ABOUT 'VOLATILE': */ /* several variables here get a volatile qualifier to silence warnings */ -/* from older (before 3.0) gccs. once the longjmp stuff is removed, */ +/* from older (before 3.0) gccs. if the longjmp stuff is removed, */ /* the volatile qualifiers should be removed as well. */ int main(int argc, char **argv, char **envp) { diff -Nru2 --exclude CVS pptp-linux-1.1.0/pptp_ctrl.c src/pptp_ctrl.c --- pptp-linux-1.1.0/pptp_ctrl.c Mon Mar 11 01:51:16 2002 +++ src/pptp_ctrl.c Thu May 30 09:31:35 2002 @@ -2,5 +2,5 @@ * C. Scott Ananian * - * $Id: pptp_ctrl.c,v 1.10 2002/03/11 01:51:16 quozl Exp $ + * $Id: pptp_ctrl.c,v 1.12 2002/05/30 08:31:35 quozl Exp $ */ @@ -239,7 +239,8 @@ if (phonenr) { strncpy(packet.phone_num, phonenr, sizeof(packet.phone_num)); - packet.phone_len = hton16 (strlen(phonenr)); + 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); } @@ -754,5 +755,5 @@ break; /* this is what we expect. */ /* log it, otherwise. */ - log("PPTP_SET_LINK_INFO recieved from peer_callid %u", + 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", diff -Nru2 --exclude CVS pptp-linux-1.1.0/pptp_gre.c src/pptp_gre.c --- pptp-linux-1.1.0/pptp_gre.c Fri Mar 1 01:23:36 2002 +++ src/pptp_gre.c Fri Aug 16 09:35:28 2002 @@ -3,5 +3,5 @@ * C. Scott Ananian * - * $Id: pptp_gre.c,v 1.9 2002/03/01 01:23:36 quozl Exp $ + * $Id: pptp_gre.c,v 1.13 2002/08/15 23:37:32 quozl Exp $ */ @@ -19,4 +19,5 @@ #include "pptp_msg.h" #include "util.h" +#include "pqueue.h" #define PACKET_MAX 8196 @@ -29,10 +30,13 @@ static u_int16_t pptp_gre_call_id, pptp_gre_peer_call_id; -/* decaps gets all the packets possible with ONE blocking read */ +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, int (*cb)(int cl, void *pack, unsigned int len), int cl); +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, int (*cb)(int cl, void *pack, unsigned int len), int cl); +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); #if 1 @@ -58,30 +62,41 @@ #endif -void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id, - int pty_fd, struct in_addr inetaddr) { +/* Open IP protocol socket */ +int pptp_gre_bind(struct in_addr inetaddr) { struct sockaddr_in src_addr; - int s, n; - pptp_gre_call_id = call_id; - pptp_gre_peer_call_id = peer_call_id; + int s = socket(AF_INET, SOCK_RAW, PPTP_PROTO); + if (s<0) { warn("socket: %s", strerror(errno)); return -1; } - /* Open IP protocol socket */ - s = socket(AF_INET, SOCK_RAW, PPTP_PROTO); - if (s<0) { warn("socket: %s", strerror(errno)); return; } src_addr.sin_family = AF_INET; src_addr.sin_addr = inetaddr; src_addr.sin_port = 0; + if (connect(s, (struct sockaddr *) &src_addr, sizeof(src_addr))<0) { - warn("connect: %s", strerror(errno)); return; + warn("connect: %s", strerror(errno)); return -1; } + + return s; +} + +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; - n = (s>pty_fd)?(s+1):(pty_fd+1); /* weird select semantics */ + /* weird select semantics */ + max_fd = gre_fd; + if (pty_fd > max_fd) max_fd = pty_fd; /* Dispatch loop */ - for (;;) { /* until error happens on s or pty_fd */ + for (;;) { /* until error happens on gre_fd or pty_fd */ struct timeval tv = {0, 0}; /* non-blocking select */ + struct timeval *tvp; fd_set rfds; int retval; @@ -89,21 +104,39 @@ /* watch terminal and socket for input */ FD_ZERO(&rfds); - FD_SET(s, &rfds); - FD_SET(pty_fd,&rfds); + FD_SET(gre_fd, &rfds); + FD_SET(pty_fd, &rfds); - /* if there is a pending ACK, do non-blocking select, + /* if there is a pending ACK, then do non-blocking select. + if there is data in the queue, then timeout after 1 second. otherwise, block until data is available */ - retval = select(n, &rfds, NULL, NULL, (ack_sent != seq_recv) ? &tv : NULL); + tvp = NULL; + if (ack_sent != seq_recv) { + tv.tv_sec = 0; + tvp = &tv; + } else if (pqueue_head != NULL) { + tv.tv_sec = 1; + tvp = &tv; + } + + retval = select(max_fd+1, &rfds, NULL, NULL, tvp); if (retval == 0 && ack_sent != seq_recv) /* if outstanding ack */ - encaps_gre(s, NULL, 0); /* send ack with no payload */ + encaps_gre(gre_fd, NULL, 0); /* send ack with no payload */ - if ((FD_ISSET(pty_fd, &rfds) && (decaps_hdlc(pty_fd, encaps_gre, s) < 0)) - || (FD_ISSET(s, &rfds) && (decaps_gre(s, encaps_hdlc, pty_fd) < 0))) - break; + if (FD_ISSET(pty_fd, &rfds)) { + if (decaps_hdlc(pty_fd, encaps_gre, gre_fd) < 0) + break; + } + if (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(s); close(pty_fd); + close(gre_fd); + close(pty_fd); } @@ -206,9 +239,12 @@ } -int decaps_gre (int fd, int (*cb)(int cl, void *pack, unsigned int len), int cl) { +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) { @@ -245,25 +281,71 @@ if (WRAPPED(ack,ack_recv)) ack_recv=ack; } - if (PPTP_GRE_IS_S(ntoh8(header->flags))) { /* payload present */ - unsigned int headersize = sizeof(*header); - unsigned int payload_len= ntoh16(header->payload_len); - u_int32_t seq = ntoh32(header->seq); - if (!PPTP_GRE_IS_A(ntoh8(header->ver))) headersize-=sizeof(header->ack); - /* check for incomplete packet (length smaller than expected) */ - if (status-headersize seq_recv) || - WRAPPED( seq, seq_recv)){ - seq_recv = seq; - first=0; - return cb(cl, buffer+ip_len+headersize, payload_len); - } else { - log("discarding out-of-order seq is %d seqrecv is %d", seq, seq_recv); - return 0; /* discard out-of-order packets */ - } + + if (!PPTP_GRE_IS_S(ntoh8(header->flags))) /* no payload present */ + return 0; /* ack, but no payload */ + + headersize = sizeof(*header); + payload_len = ntoh16(header->payload_len); + seq = ntoh32(header->seq); + + 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) { + log("discarding truncated packet (expected %d, got %d bytes)", + payload_len, status-headersize); + return 0; } - return 0; /* ack, but no payload */ + + /* check for out-of-order sequence number */ + /* (handle sequence number wrap-around, and try to do it right) */ + if ( first || (seq == seq_recv+1) || + WRAPPED(seq, seq_recv)){ + log("accepting packet %d", seq); + first=0; + seq_recv = seq; + return callback(cl, buffer+ip_len+headersize, payload_len); + + } else if ( seq < seq_recv+1 || WRAPPED(seq_recv,seq) ) { + log("discarding duplicate or old packet %d (expecting %d)", + seq, seq_recv+1); + + } else if ( seq < seq_recv+MISSING_WINDOW || + WRAPPED(seq, seq_recv+MISSING_WINDOW) ) { + log("buffering out-of-order packet %d (expecting %d)", seq, seq_recv+1); + pqueue_add(seq, buffer+ip_len+headersize, payload_len); + + } else { + log("discarding bogus packet %d (expecting %d)", seq, seq_recv+1); + } + + return 0; } + +int dequeue_gre (callback_t callback, int cl) { + pqueue_t *head; + int status; + time_t now = time(NULL); + + head = pqueue_head(); + if (head == NULL) return 0; + + while ( (head->seq == seq_recv+1) || + (WRAPPED(head->seq, seq_recv)) || + (head->expires < now) ) { + if (head->expires < now) + log("timeout waiting for %d packets", head->seq - seq_recv - 1); + 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; +} + int encaps_gre (int fd, void *pack, unsigned int len) { union { diff -Nru2 --exclude CVS pptp-linux-1.1.0/pptp_gre.h src/pptp_gre.h --- pptp-linux-1.1.0/pptp_gre.h Sat Dec 23 08:19:51 2000 +++ src/pptp_gre.h Thu Jul 18 03:34:30 2002 @@ -3,9 +3,8 @@ * C. Scott Ananian * - * $Id: pptp_gre.h,v 1.1.1.1 2000/12/23 08:19:51 scott Exp $ + * $Id: pptp_gre.h,v 1.2 2002/07/18 02:34:30 quozl Exp $ */ -/*void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id, - char *pty, char *inetaddr);*/ +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, struct in_addr inetaddr); + int pty_fd, int gre_fd); diff -Nru2 --exclude CVS pptp-linux-1.1.0/pqueue.c src/pqueue.c --- pptp-linux-1.1.0/pqueue.c Thu Jan 1 01:00:00 1970 +++ src/pqueue.c Thu Aug 15 09:11:43 2002 @@ -0,0 +1,86 @@ +#include +#include +#include + +#include "util.h" // for log() +#include "pqueue.h" + +static pqueue_t *pq_head = NULL, *pq_tail = NULL; + +int pqueue_add (int seq, unsigned char *packet, int packlen) { + pqueue_t *newent, *point; + + newent = (pqueue_t *)calloc(1, sizeof(pqueue_t)); + if (!newent) { + log("error allocating newent: %s", strerror(errno)); + return -1; + } + + newent->packet = (unsigned char *)malloc(packlen); + if (!newent->packet) { + log("error allocating packet: %s", strerror(errno)); + return -1; + } + + memcpy(newent->packet, packet, packlen); + newent->seq = seq; + newent->packlen = packlen; + newent->expires = time(NULL) + MISSING_TIMEOUT; + + for (point = pq_head; point != NULL; point = point->next) { + if (point->seq == seq) { + // queue already contains this packet + log("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 + 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 + 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) { + log("adding %d to empty queue", seq); + pq_head = newent; + } else { + 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) { + 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; + free(point->packet); + free(point); + return 0; +} + +pqueue_t *pqueue_head () { + return pq_head; +} diff -Nru2 --exclude CVS pptp-linux-1.1.0/pqueue.h src/pqueue.h --- pptp-linux-1.1.0/pqueue.h Thu Jan 1 01:00:00 1970 +++ src/pqueue.h Fri Aug 16 09:35:28 2002 @@ -0,0 +1,26 @@ +#ifndef PQUEUE_H +#define PQUEUE_H + +#include + +/* wait this many seconds for missing packets before forgetting about them */ +#define MISSING_TIMEOUT 5 + +/* assume packet is bad/spoofed if it's more than this many seqs ahead */ +#define MISSING_WINDOW 50 + +/* Packet queue structure: linked list of packets received out-of-order */ +typedef struct pqueue { + struct pqueue *next; + struct pqueue *prev; + int seq; + time_t expires; + unsigned char *packet; + int packlen; +} pqueue_t; + +int pqueue_add (int seq, unsigned char *packet, int packlen); +int pqueue_del (pqueue_t *point); +pqueue_t *pqueue_head (); + +#endif /* PQUEUE_H */