1 /* pptp_gre.c -- encapsulate PPP in PPTP-GRE.
2 * Handle the IP Protocol 47 portion of PPTP.
3 * C. Scott Ananian <cananian@alumni.princeton.edu>
5 * $Id: pptp_gre.c,v 1.39 2005/07/11 03:23:48 quozl Exp $
9 #include <netinet/in.h>
10 #include <arpa/inet.h>
11 #include <sys/socket.h>
25 #define PACKET_MAX 8196
26 /* test for a 32 bit counter overflow */
27 #define WRAPPED( curseq, lastseq) \
28 ((((curseq) & 0xffffff00) == 0) && \
29 (((lastseq) & 0xffffff00 ) == 0xffffff00))
31 static u_int32_t ack_sent
, ack_recv
;
32 static u_int32_t seq_sent
, seq_recv
;
33 static u_int16_t pptp_gre_call_id
, pptp_gre_peer_call_id
;
36 typedef int (*callback_t
)(int cl
, void *pack
, unsigned int len
);
38 /* decaps_hdlc gets all the packets possible with ONE blocking read */
39 /* returns <0 if read() call fails */
40 int decaps_hdlc(int fd
, callback_t callback
, int cl
);
41 int encaps_hdlc(int fd
, void *pack
, unsigned int len
);
42 int decaps_gre (int fd
, callback_t callback
, int cl
);
43 int encaps_gre (int fd
, void *pack
, unsigned int len
);
44 int dequeue_gre(callback_t callback
, int cl
);
48 void print_packet(int fd
, void *pack
, unsigned int len
)
50 unsigned char *b
= (unsigned char *)pack
;
52 FILE *out
= fdopen(fd
, "w");
53 fprintf(out
,"-- begin packet (%u) --\n", len
);
54 for (i
= 0; i
< len
; i
+= 16) {
55 for (j
= 0; j
< 8; j
++)
56 if (i
+ 2 * j
+ 1 < len
)
57 fprintf(out
, "%02x%02x ",
58 (unsigned int) b
[i
+ 2 * j
],
59 (unsigned int) b
[i
+ 2 * j
+ 1]);
60 else if (i
+ 2 * j
< len
)
61 fprintf(out
, "%02x ", (unsigned int) b
[i
+ 2 * j
]);
64 fprintf(out
, "-- end packet --\n");
69 /*** time_now_usecs ***********************************************************/
70 uint64_t time_now_usecs()
73 gettimeofday(&tv
, NULL
);
74 return (tv
.tv_sec
* 1000000) + tv
.tv_usec
;
77 /*** Open IP protocol socket **************************************************/
78 int pptp_gre_bind(struct in_addr inetaddr
)
80 struct sockaddr_in src_addr
, loc_addr
;
81 extern struct in_addr localbind
;
82 int s
= socket(AF_INET
, SOCK_RAW
, PPTP_PROTO
);
83 if (s
< 0) { warn("socket: %s", strerror(errno
)); return -1; }
84 if (localbind
.s_addr
!= INADDR_NONE
) {
85 bzero(&loc_addr
, sizeof(loc_addr
));
86 loc_addr
.sin_family
= AF_INET
;
87 loc_addr
.sin_addr
= localbind
;
88 if (bind(s
, (struct sockaddr
*) &loc_addr
, sizeof(loc_addr
)) != 0) {
89 warn("bind: %s", strerror(errno
)); close(s
); return -1;
92 src_addr
.sin_family
= AF_INET
;
93 src_addr
.sin_addr
= inetaddr
;
94 src_addr
.sin_port
= 0;
95 if (connect(s
, (struct sockaddr
*) &src_addr
, sizeof(src_addr
)) < 0) {
96 warn("connect: %s", strerror(errno
)); close(s
); return -1;
101 /*** pptp_gre_copy ************************************************************/
102 void pptp_gre_copy(u_int16_t call_id
, u_int16_t peer_call_id
,
103 int pty_fd
, int gre_fd
)
106 pptp_gre_call_id
= call_id
;
107 pptp_gre_peer_call_id
= peer_call_id
;
108 /* Pseudo-terminal already open. */
109 ack_sent
= ack_recv
= seq_sent
= seq_recv
= 0;
110 /* weird select semantics */
112 if (pty_fd
> max_fd
) max_fd
= pty_fd
;
114 for (;;) { /* until error happens on gre_fd or pty_fd */
115 struct timeval tv
= {0, 0};
120 int block_usecs
= -1; /* wait forever */
121 /* watch terminal and socket for input */
123 FD_SET(gre_fd
, &rfds
);
124 FD_SET(pty_fd
, &rfds
);
126 * if there are multiple pending ACKs, then do a minimal timeout;
127 * else if there is a single pending ACK then timeout after 0,5 seconds;
128 * else block until data is available.
130 if (ack_sent
!= seq_recv
) {
131 if (ack_sent
+ 1 == seq_recv
) /* u_int wrap-around safe */
132 block_usecs
= 500000;
134 /* don't use zero, this will force a resceduling */
135 /* when calling select(), giving pppd a chance to */
139 /* otherwise block_usecs == -1, which means wait forever */
141 * If there is a packet in the queue, then don't wait longer than
142 * the time remaining until it expires.
144 head
= pqueue_head();
146 int expiry_time
= pqueue_expiry_time(head
);
147 if (block_usecs
== -1 || expiry_time
< block_usecs
)
148 block_usecs
= expiry_time
;
150 if (block_usecs
== -1) {
154 tv
.tv_usec
= block_usecs
;
155 tv
.tv_sec
= tv
.tv_usec
/ 1000000;
156 tv
.tv_usec
%= 1000000;
158 retval
= select(max_fd
+ 1, &rfds
, NULL
, NULL
, tvp
);
159 if (FD_ISSET(pty_fd
, &rfds
)) {
160 if (decaps_hdlc(pty_fd
, encaps_gre
, gre_fd
) < 0)
162 } else if (retval
== 0 && ack_sent
!= seq_recv
) {
163 /* if outstanding ack */
164 /* send ack with no payload */
165 encaps_gre(gre_fd
, NULL
, 0);
167 if (FD_ISSET(gre_fd
, &rfds
)) {
168 if (decaps_gre (gre_fd
, encaps_hdlc
, pty_fd
) < 0)
171 if (dequeue_gre (encaps_hdlc
, pty_fd
) < 0)
174 /* Close up when done. */
179 #define HDLC_FLAG 0x7E
180 #define HDLC_ESCAPE 0x7D
181 #define HDLC_TRANSPARENCY 0x20
183 /* ONE blocking read per call; dispatches all packets possible */
184 /* returns 0 on success, or <0 on read failure */
185 int decaps_hdlc(int fd
, int (*cb
)(int cl
, void *pack
, unsigned int len
), int cl
)
187 unsigned char buffer
[PACKET_MAX
];
188 unsigned int start
= 0;
191 static unsigned int len
= 0, escape
= 0;
192 static unsigned char copy
[PACKET_MAX
];
193 static int checkedsync
= 0;
194 /* start is start of packet. end is end of buffer data */
195 /* this is the only blocking read we will allow */
196 if ((end
= read (fd
, buffer
, sizeof(buffer
))) <= 0) {
197 int saved_errno
= errno
;
198 warn("short read (%d): %s", end
, strerror(saved_errno
));
199 switch (saved_errno
) {
201 int optval
, optlen
= sizeof(optval
);
202 warn("transmitted GRE packet triggered an ICMP destination unreachable, fragmentation needed, or exceeds the MTU of the network interface");
204 if(getsockopt(fd
, IPPROTO_IP
, IP_MTU
, &optval
, &optlen
) < 0)
205 warn("getsockopt: %s", strerror(errno
));
206 warn("getsockopt: IP_MTU: %d\n", optval
);
210 warn("pppd may have shutdown, see pppd log");
215 /* warn if the sync options of ppp and pptp don't match */
218 if( buffer
[0] == HDLC_FLAG
){
220 warn( "pptp --sync option is active, "
221 "yet the ppp mode is asynchronous!\n");
224 warn( "The ppp mode is synchronous, "
225 "yet no pptp --sync option is specified!\n");
228 /* this handling is pretty simple thanks to N_HDLC */
229 if ((status
= cb (cl
, buffer
, end
)) < 0)
230 return status
; /* error-check */
233 /* asynchronous mode */
234 while (start
< end
) {
235 /* Copy to 'copy' and un-escape as we go. */
236 while (buffer
[start
] != HDLC_FLAG
) {
237 if ((escape
== 0) && buffer
[start
] == HDLC_ESCAPE
) {
238 escape
= HDLC_TRANSPARENCY
;
240 if (len
< PACKET_MAX
)
241 copy
[len
++] = buffer
[start
] ^ escape
;
246 return 0; /* No more data, but the frame is not complete yet. */
248 /* found flag. skip past it */
250 /* check for over-short packets and silently discard, as per RFC1662 */
251 if ((len
< 4) || (escape
!= 0)) {
255 /* check, then remove the 16-bit FCS checksum field */
256 if (pppfcs16 (PPPINITFCS16
, copy
, len
) != PPPGOODFCS16
)
257 warn("Bad Frame Check Sequence during PPP to GRE decapsulation");
258 len
-= sizeof(u_int16_t
);
259 /* so now we have a packet of length 'len' in 'copy' */
260 if ((status
= cb (cl
, copy
, len
)) < 0)
261 return status
; /* error-check */
262 /* Great! Let's do more! */
266 /* No more data to process. */
269 /*** Make stripped packet into HDLC packet ************************************/
270 int encaps_hdlc(int fd
, void *pack
, unsigned int len
)
272 unsigned char *source
= (unsigned char *)pack
;
273 unsigned char dest
[2 * PACKET_MAX
+ 2]; /* largest expansion possible */
274 unsigned int pos
= 0, i
;
276 /* in synchronous mode there is little to do */
278 return write(fd
, source
, len
);
279 /* asynchronous mode */
280 /* Compute the FCS */
281 fcs
= pppfcs16(PPPINITFCS16
, source
, len
) ^ 0xFFFF;
282 /* start character */
283 dest
[pos
++] = HDLC_FLAG
;
284 /* escape the payload */
285 for (i
= 0; i
< len
+ 2; i
++) {
286 /* wacked out assignment to add FCS to end of source buffer */
288 (i
< len
)?source
[i
]:(i
== len
)?(fcs
& 0xFF):((fcs
>> 8) & 0xFF);
289 if (pos
>= sizeof(dest
)) break; /* truncate on overflow */
290 if ( (c
< 0x20) || (c
== HDLC_FLAG
) || (c
== HDLC_ESCAPE
) ) {
291 dest
[pos
++] = HDLC_ESCAPE
;
292 if (pos
< sizeof(dest
))
293 dest
[pos
++] = c
^ 0x20;
297 /* tack on the end-flag */
298 if (pos
< sizeof(dest
))
299 dest
[pos
++] = HDLC_FLAG
;
300 /* now write this packet */
301 return write(fd
, dest
, pos
);
304 /*** decaps_gre ***************************************************************/
305 int decaps_gre (int fd
, callback_t callback
, int cl
)
307 unsigned char buffer
[PACKET_MAX
+ 64 /*ip header*/];
308 struct pptp_gre_header
*header
;
309 int status
, ip_len
= 0;
310 static int first
= 1;
311 unsigned int headersize
;
312 unsigned int payload_len
;
315 if ((status
= read (fd
, buffer
, sizeof(buffer
))) <= 0) {
316 warn("short read (%d): %s", status
, strerror(errno
));
320 /* strip off IP header, if present */
321 if ((buffer
[0] & 0xF0) == 0x40)
322 ip_len
= (buffer
[0] & 0xF) * 4;
323 header
= (struct pptp_gre_header
*)(buffer
+ ip_len
);
324 /* verify packet (else discard) */
325 if ( /* version should be 1 */
326 ((ntoh8(header
->ver
) & 0x7F) != PPTP_GRE_VER
) ||
327 /* PPTP-GRE protocol for PPTP */
328 (ntoh16(header
->protocol
) != PPTP_GRE_PROTO
)||
329 /* flag C should be clear */
330 PPTP_GRE_IS_C(ntoh8(header
->flags
)) ||
331 /* flag R should be clear */
332 PPTP_GRE_IS_R(ntoh8(header
->flags
)) ||
333 /* flag K should be set */
334 (!PPTP_GRE_IS_K(ntoh8(header
->flags
))) ||
335 /* routing and recursion ctrl = 0 */
336 ((ntoh8(header
->flags
)&0xF) != 0)) {
337 /* if invalid, discard this packet */
338 warn("Discarding GRE: %X %X %X %X %X %X",
339 ntoh8(header
->ver
)&0x7F, ntoh16(header
->protocol
),
340 PPTP_GRE_IS_C(ntoh8(header
->flags
)),
341 PPTP_GRE_IS_R(ntoh8(header
->flags
)),
342 PPTP_GRE_IS_K(ntoh8(header
->flags
)),
343 ntoh8(header
->flags
) & 0xF);
347 /* silently discard packets not for this call */
348 if (ntoh16(header
->call_id
) != pptp_gre_call_id
) {
350 log("Discarding for other call : %d %d",
351 ntoh16(header
->call_id
), pptp_gre_call_id
);
352 if (pptp_gre_call_id
== 0) {
353 pptp_gre_call_id
= ntoh16(header
->call_id
);
358 /* test if acknowledgement present */
359 if (PPTP_GRE_IS_A(ntoh8(header
->ver
))) {
360 u_int32_t ack
= (PPTP_GRE_IS_S(ntoh8(header
->flags
)))?
361 header
->ack
:header
->seq
; /* ack in different place if S = 0 */
363 if (ack
> ack_recv
) ack_recv
= ack
;
364 /* also handle sequence number wrap-around */
365 if (WRAPPED(ack
,ack_recv
)) ack_recv
= ack
;
366 if (ack_recv
== stats
.pt
.seq
) {
367 int rtt
= time_now_usecs() - stats
.pt
.time
;
368 stats
.rtt
= (stats
.rtt
+ rtt
) / 2;
371 /* test if payload present */
372 if (!PPTP_GRE_IS_S(ntoh8(header
->flags
)))
373 return 0; /* ack, but no payload */
374 headersize
= sizeof(*header
);
375 payload_len
= ntoh16(header
->payload_len
);
376 seq
= ntoh32(header
->seq
);
377 /* no ack present? */
378 if (!PPTP_GRE_IS_A(ntoh8(header
->ver
))) headersize
-= sizeof(header
->ack
);
379 /* check for incomplete packet (length smaller than expected) */
380 if (status
- headersize
< payload_len
) {
381 warn("discarding truncated packet (expected %d, got %d bytes)",
382 payload_len
, status
- headersize
);
383 stats
.rx_truncated
++;
386 /* check for expected sequence number */
387 if ( first
|| (seq
== seq_recv
+ 1)) { /* wrap-around safe */
388 if ( log_level
>= 2 )
389 log("accepting packet %d", seq
);
393 return callback(cl
, buffer
+ ip_len
+ headersize
, payload_len
);
394 /* out of order, check if the number is too low and discard the packet.
395 * (handle sequence number wrap-around, and try to do it right) */
396 } else if ( seq
< seq_recv
+ 1 || WRAPPED(seq_recv
, seq
) ) {
397 if ( log_level
>= 1 )
398 log("discarding duplicate or old packet %d (expecting %d)",
401 /* sequence number too high, is it reasonably close? */
402 } else if ( seq
< seq_recv
+ MISSING_WINDOW
||
403 WRAPPED(seq
, seq_recv
+ MISSING_WINDOW
) ) {
405 if ( log_level
>= 1 )
406 log("%s packet %d (expecting %d, lost or reordered)",
407 disable_buffer
? "accepting" : "buffering",
409 if ( disable_buffer
) {
411 stats
.rx_lost
+= seq
- seq_recv
- 1;
412 return callback(cl
, buffer
+ ip_len
+ headersize
, payload_len
);
414 pqueue_add(seq
, buffer
+ ip_len
+ headersize
, payload_len
);
416 /* no, packet must be discarded */
418 if ( log_level
>= 1 )
419 warn("discarding bogus packet %d (expecting %d)",
426 /*** dequeue_gre **************************************************************/
427 int dequeue_gre (callback_t callback
, int cl
)
431 /* process packets in the queue that either are expected or have
433 head
= pqueue_head();
434 while ( head
!= NULL
&&
435 ( (head
->seq
== seq_recv
+ 1) || /* wrap-around safe */
436 (pqueue_expiry_time(head
) <= 0)
439 /* if it is timed out... */
440 if (head
->seq
!= seq_recv
+ 1 ) { /* wrap-around safe */
441 stats
.rx_lost
+= head
->seq
- seq_recv
- 1;
443 log("timeout waiting for %d packets", head
->seq
- seq_recv
- 1);
446 log("accepting %d from queue", head
->seq
);
447 seq_recv
= head
->seq
;
448 status
= callback(cl
, head
->packet
, head
->packlen
);
452 head
= pqueue_head();
457 /*** encaps_gre ***************************************************************/
458 int encaps_gre (int fd
, void *pack
, unsigned int len
)
460 struct pptp_gre_header header
;
461 struct iovec iov
[2] = { { &header
, 0 }, { pack
, len
} };
462 static u_int32_t seq
= 1; /* first sequence number sent must be 1 */
463 unsigned int header_len
;
465 /* package this up in a GRE shell. */
466 header
.flags
= hton8 (PPTP_GRE_FLAG_K
);
467 header
.ver
= hton8 (PPTP_GRE_VER
);
468 header
.protocol
= hton16(PPTP_GRE_PROTO
);
469 header
.payload_len
= hton16(len
);
470 header
.call_id
= hton16(pptp_gre_peer_call_id
);
471 /* special case ACK with no payload */
473 if (ack_sent
!= seq_recv
) {
474 header
.ver
|= hton8(PPTP_GRE_FLAG_A
);
475 header
.payload_len
= hton16(0);
476 /* ack is in odd place because S == 0 */
477 header
.seq
= hton32(seq_recv
);
479 rc
= write(fd
, &header
, sizeof(header
) - sizeof(header
.seq
));
482 } else if (rc
< sizeof(header
) - sizeof(header
.seq
)) {
488 } else return 0; /* we don't need to send ACK */
489 } /* explicit brace to avoid ambiguous `else' warning */
490 /* send packet with payload */
491 header
.flags
|= hton8(PPTP_GRE_FLAG_S
);
492 header
.seq
= hton32(seq
);
493 if (ack_sent
!= seq_recv
) { /* send ack with this message */
494 header
.ver
|= hton8(PPTP_GRE_FLAG_A
);
495 header
.ack
= hton32(seq_recv
);
497 header_len
= sizeof(header
);
498 } else { /* don't send ack */
499 header_len
= sizeof(header
) - sizeof(header
.ack
);
501 /* save final header length */
502 iov
[0].iov_len
= header_len
;
503 /* record and increment sequence numbers */
504 seq_sent
= seq
; seq
++;
505 /* write this baby out to the net */
506 rc
= writev(fd
, iov
, 2);
509 } else if (rc
< header_len
+ len
) {
513 stats
.pt
.seq
= seq_sent
;
514 stats
.pt
.time
= time_now_usecs();