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.1.1.1 2002/07/25 06:52:39 honor Exp $
9 #include <netinet/in.h>
10 #include <arpa/inet.h>
11 #include <sys/socket.h>
22 #define PACKET_MAX 8196
23 /* test for a 32 bit counter overflow */
24 #define WRAPPED( curseq, lastseq) \
25 ((((curseq) & 0xffffff00)==0) && (((lastseq) & 0xffffff00 )==0xffffff00))
27 static u_int32_t ack_sent
, ack_recv
;
28 static u_int32_t seq_sent
, seq_recv
;
29 static u_int16_t pptp_gre_call_id
, pptp_gre_peer_call_id
;
31 /* decaps gets all the packets possible with ONE blocking read */
32 /* returns <0 if read() call fails */
33 int decaps_hdlc(int fd
, int (*cb
)(int cl
, void *pack
, unsigned int len
), int cl
);
34 int encaps_hdlc(int fd
, void *pack
, unsigned int len
);
35 int decaps_gre (int fd
, int (*cb
)(int cl
, void *pack
, unsigned int len
), int cl
);
36 int encaps_gre (int fd
, void *pack
, unsigned int len
);
40 void print_packet(int fd
, void *pack
, unsigned int len
) {
41 unsigned char *b
= (unsigned char *)pack
;
43 FILE *out
= fdopen(fd
, "w");
45 fprintf(out
,"-- begin packet (%u) --\n", len
);
46 for (i
=0; i
<len
; i
+=16) {
49 fprintf(out
, "%02x%02x ",
50 (unsigned int) b
[i
+2*j
], (unsigned int) b
[i
+2*j
+1]);
52 fprintf(out
, "%02x ", (unsigned int) b
[i
+2*j
]);
55 fprintf(out
, "-- end packet --\n");
60 void pptp_gre_copy(u_int16_t call_id
, u_int16_t peer_call_id
,
61 int pty_fd
, struct in_addr inetaddr
) {
62 struct sockaddr_in src_addr
;
65 pptp_gre_call_id
= call_id
;
66 pptp_gre_peer_call_id
= peer_call_id
;
68 /* Open IP protocol socket */
69 s
= socket(AF_INET
, SOCK_RAW
, PPTP_PROTO
);
70 if (s
<0) { warn("socket: %s", strerror(errno
)); return; }
71 src_addr
.sin_family
= AF_INET
;
72 src_addr
.sin_addr
= inetaddr
;
73 src_addr
.sin_port
= 0;
74 if (connect(s
, (struct sockaddr
*) &src_addr
, sizeof(src_addr
))<0) {
75 warn("connect: %s", strerror(errno
)); return;
77 /* Pseudo-terminal already open. */
79 ack_sent
= ack_recv
= seq_sent
= seq_recv
= 0;
81 n
= (s
>pty_fd
)?(s
+1):(pty_fd
+1); /* weird select semantics */
84 for (;;) { /* until error happens on s or pty_fd */
85 struct timeval tv
= {0, 0}; /* non-blocking select */
89 /* watch terminal and socket for input */
94 /* if there is a pending ACK, do non-blocking select,
95 otherwise, block until data is available */
96 retval
= select(n
, &rfds
, NULL
, NULL
, (ack_sent
!= seq_recv
) ? &tv
: NULL
);
98 if (retval
== 0 && ack_sent
!= seq_recv
) /* if outstanding ack */
99 encaps_gre(s
, NULL
, 0); /* send ack with no payload */
101 if ((FD_ISSET(pty_fd
, &rfds
) && (decaps_hdlc(pty_fd
, encaps_gre
, s
) < 0))
102 || (FD_ISSET(s
, &rfds
) && (decaps_gre(s
, encaps_hdlc
, pty_fd
) < 0)))
106 /* Close up when done. */
107 close(s
); close(pty_fd
);
110 #define HDLC_FLAG 0x7E
111 #define HDLC_ESCAPE 0x7D
112 #define HDLC_TRANSPARENCY 0x20
114 /* ONE blocking read per call; dispatches all packets possible */
115 /* returns 0 on success, or <0 on read failure */
116 int decaps_hdlc(int fd
, int (*cb
)(int cl
, void *pack
, unsigned int len
), int cl
) {
117 unsigned char buffer
[PACKET_MAX
];
118 unsigned int start
= 0;
122 static unsigned int len
= 0, escape
= 0;
123 static unsigned char copy
[PACKET_MAX
];
125 /* start is start of packet. end is end of buffer data */
126 /* this is the only blocking read we will allow */
128 if ((end
= read (fd
, buffer
, sizeof(buffer
))) <= 0) {
129 log ("short read (%u): %s", end
, strerror(errno
));
133 while (start
< end
) {
135 /* Copy to 'copy' and un-escape as we go. */
137 while (buffer
[start
] != HDLC_FLAG
) {
138 if ((escape
== 0) && buffer
[start
] == HDLC_ESCAPE
) {
139 escape
= HDLC_TRANSPARENCY
;
141 if (len
< PACKET_MAX
)
142 copy
[len
++] = buffer
[start
] ^ escape
;
148 return 0; /* No more data, but the frame is not complete yet. */
151 /* found flag. skip past it */
154 /* check for over-short packets and silently discard, as per RFC1662 */
155 if ((len
< 4) || (escape
!= 0)) {
159 /* check, then remove the 16-bit FCS checksum field */
160 if (pppfcs16 (PPPINITFCS16
, copy
, len
) != PPPGOODFCS16
)
161 log("Bad Frame Check Sequence during PPP to GRE decapsulation");
162 len
-= sizeof(u_int16_t
);
164 /* so now we have a packet of length 'len' in 'copy' */
165 if ((status
= cb (cl
, copy
, len
)) < 0)
166 return status
; /* error-check */
168 /* Great! Let's do more! */
173 /* No more data to process. */
176 /* Make stripped packet into HDLC packet */
177 int encaps_hdlc(int fd
, void *pack
, unsigned int len
) {
178 unsigned char *source
= (unsigned char *)pack
;
179 unsigned char dest
[2*PACKET_MAX
+2]; /* largest expansion possible */
180 unsigned int pos
=0, i
;
183 /* Compute the FCS */
184 fcs
= pppfcs16(PPPINITFCS16
, source
, len
) ^ 0xFFFF;
186 /* start character */
187 dest
[pos
++]=HDLC_FLAG
;
188 /* escape the payload */
189 for (i
=0; i
<len
+2; i
++) {
190 /* wacked out assignment to add FCS to end of source buffer */
191 unsigned char c
= (i
<len
)?source
[i
]:(i
==len
)?(fcs
&0xFF):((fcs
>>8)&0xFF);
192 if (pos
>=sizeof(dest
)) break; /* truncate on overflow */
193 if ( (c
<0x20) || (c
==HDLC_FLAG
) || (c
==HDLC_ESCAPE
) ) {
194 dest
[pos
++]=HDLC_ESCAPE
;
195 if (pos
<sizeof(dest
))
200 /* tack on the end-flag */
201 if (pos
<sizeof(dest
))
202 dest
[pos
++]=HDLC_FLAG
;
204 /* now write this packet */
205 return write(fd
, dest
, pos
);
208 int decaps_gre (int fd
, int (*cb
)(int cl
, void *pack
, unsigned int len
), int cl
) {
209 unsigned char buffer
[PACKET_MAX
+64/*ip header*/];
210 struct pptp_gre_header
*header
;
211 int status
, ip_len
=0;
214 if ((status
= read (fd
, buffer
, sizeof(buffer
))) <= 0) {
215 log("short read (%u): %s", status
, strerror(errno
));
219 /* strip off IP header, if present */
220 if ((buffer
[0]&0xF0)==0x40)
221 ip_len
= (buffer
[0]&0xF)*4;
222 header
= (struct pptp_gre_header
*)(buffer
+ip_len
);
224 /* verify packet (else discard) */
225 if (((ntoh8(header
->ver
)&0x7F)!=PPTP_GRE_VER
) || /* version should be 1 */
226 (ntoh16(header
->protocol
)!=PPTP_GRE_PROTO
)|| /* GRE protocol for PPTP */
227 PPTP_GRE_IS_C(ntoh8(header
->flags
)) || /* flag C should be clear */
228 PPTP_GRE_IS_R(ntoh8(header
->flags
)) || /* flag R should be clear */
229 (!PPTP_GRE_IS_K(ntoh8(header
->flags
))) || /* flag K should be set */
230 ((ntoh8(header
->flags
)&0xF)!=0)) { /* routing and recursion ctrl = 0 */
231 /* if invalid, discard this packet */
232 log("Discarding GRE: %X %X %X %X %X %X",
233 ntoh8(header
->ver
)&0x7F, ntoh16(header
->protocol
),
234 PPTP_GRE_IS_C(ntoh8(header
->flags
)),
235 PPTP_GRE_IS_R(ntoh8(header
->flags
)),
236 PPTP_GRE_IS_K(ntoh8(header
->flags
)),
237 ntoh8(header
->flags
)&0xF);
240 if (PPTP_GRE_IS_A(ntoh8(header
->ver
))) { /* acknowledgement present */
241 u_int32_t ack
= (PPTP_GRE_IS_S(ntoh8(header
->flags
)))?
242 header
->ack
:header
->seq
; /* ack in different place if S=0 */
243 if (ack
> ack_recv
) ack_recv
= ack
;
244 /* also handle sequence number wrap-around */
245 if (WRAPPED(ack
,ack_recv
)) ack_recv
=ack
;
247 if (PPTP_GRE_IS_S(ntoh8(header
->flags
))) { /* payload present */
248 unsigned int headersize
= sizeof(*header
);
249 unsigned int payload_len
= ntoh16(header
->payload_len
);
250 u_int32_t seq
= ntoh32(header
->seq
);
251 if (!PPTP_GRE_IS_A(ntoh8(header
->ver
))) headersize
-=sizeof(header
->ack
);
252 /* check for incomplete packet (length smaller than expected) */
253 if (status
-headersize
<payload_len
) return 0;
254 /* check for out-of-order sequence number */
255 /* (handle sequence number wrap-around, and try to do it right) */
256 if ( first
|| (seq
> seq_recv
) ||
257 WRAPPED( seq
, seq_recv
)){
260 return cb(cl
, buffer
+ip_len
+headersize
, payload_len
);
262 log("discarding out-of-order seq is %d seqrecv is %d", seq
, seq_recv
);
263 return 0; /* discard out-of-order packets */
266 return 0; /* ack, but no payload */
268 int encaps_gre (int fd
, void *pack
, unsigned int len
) {
270 struct pptp_gre_header header
;
271 unsigned char buffer
[PACKET_MAX
+sizeof(struct pptp_gre_header
)];
273 static u_int32_t seq
=0;
274 unsigned int header_len
;
276 /* package this up in a GRE shell. */
277 u
.header
.flags
= hton8 (PPTP_GRE_FLAG_K
);
278 u
.header
.ver
= hton8 (PPTP_GRE_VER
);
279 u
.header
.protocol
= hton16(PPTP_GRE_PROTO
);
280 u
.header
.payload_len
= hton16(len
);
281 u
.header
.call_id
= hton16(pptp_gre_peer_call_id
);
283 /* special case ACK with no payload */
285 if (ack_sent
!= seq_recv
) {
286 u
.header
.ver
|= hton8(PPTP_GRE_FLAG_A
);
287 u
.header
.payload_len
= hton16(0);
288 u
.header
.seq
= hton32(seq_recv
); /* ack is in odd place because S=0 */
290 return write(fd
, &u
.header
, sizeof(u
.header
)-sizeof(u
.header
.seq
));
291 } else return 0; /* we don't need to send ACK */
292 } /* explicit brace to avoid ambiguous `else' warning */
293 /* send packet with payload */
294 u
.header
.flags
|= hton8(PPTP_GRE_FLAG_S
);
295 u
.header
.seq
= hton32(seq
);
296 if (ack_sent
!= seq_recv
) { /* send ack with this message */
297 u
.header
.ver
|= hton8(PPTP_GRE_FLAG_A
);
298 u
.header
.ack
= hton32(seq_recv
);
300 header_len
= sizeof(u
.header
);
301 } else { /* don't send ack */
302 header_len
= sizeof(u
.header
) - sizeof(u
.header
.ack
);
304 if (header_len
+len
>=sizeof(u
.buffer
)) return 0; /* drop this, it's too big */
305 /* copy payload into buffer */
306 memcpy(u
.buffer
+header_len
, pack
, len
);
307 /* record and increment sequence numbers */
308 seq_sent
= seq
; seq
++;
309 /* write this baby out to the net */
310 /* print_packet(2, u.buffer, header_len+len); */
311 return write(fd
, u
.buffer
, header_len
+len
);