blob: 63d5e584b272a118ef3bfc46d9ab8ce808d75f75
1 | /*********************************************************************** |
2 | * |
3 | * common.c |
4 | * |
5 | * Implementation of user-space PPPoE redirector for Linux. |
6 | * |
7 | * Common functions used by PPPoE client and server |
8 | * |
9 | * Copyright (C) 2000 by Roaring Penguin Software Inc. |
10 | * |
11 | * This program may be distributed according to the terms of the GNU |
12 | * General Public License, version 2 or (at your option) any later version. |
13 | * |
14 | * LIC: GPL |
15 | * |
16 | ***********************************************************************/ |
17 | |
18 | static char const RCSID[] = |
19 | "$Id$"; |
20 | /* For vsnprintf prototype */ |
21 | #define _ISOC99_SOURCE 1 |
22 | |
23 | /* For seteuid prototype */ |
24 | #define _BSD_SOURCE 1 |
25 | |
26 | #include "pppoe.h" |
27 | |
28 | |
29 | #ifdef HAVE_SYSLOG_H |
30 | #include <syslog.h> |
31 | #include <android/log.h> |
32 | #define syslog(prio, fmt...) \ |
33 | __android_log_print(prio, "PPPOE", fmt) |
34 | #endif |
35 | |
36 | #include <string.h> |
37 | #include <errno.h> |
38 | #include <stdlib.h> |
39 | #include <stdarg.h> |
40 | |
41 | #ifdef HAVE_UNISTD_H |
42 | #include <unistd.h> |
43 | #endif |
44 | |
45 | #include <sys/types.h> |
46 | #include <pwd.h> |
47 | |
48 | #include "../../ppp/pppd/pathnames.h" |
49 | /* Are we running SUID or SGID? */ |
50 | int IsSetID = 0; |
51 | |
52 | static uid_t saved_uid = -2; |
53 | static uid_t saved_gid = -2; |
54 | |
55 | /********************************************************************** |
56 | *%FUNCTION: parsePacket |
57 | *%ARGUMENTS: |
58 | * packet -- the PPPoE discovery packet to parse |
59 | * func -- function called for each tag in the packet |
60 | * extra -- an opaque data pointer supplied to parsing function |
61 | *%RETURNS: |
62 | * 0 if everything went well; -1 if there was an error |
63 | *%DESCRIPTION: |
64 | * Parses a PPPoE discovery packet, calling "func" for each tag in the packet. |
65 | * "func" is passed the additional argument "extra". |
66 | ***********************************************************************/ |
67 | int |
68 | parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra) |
69 | { |
70 | UINT16_t len = ntohs(packet->length); |
71 | unsigned char *curTag; |
72 | UINT16_t tagType, tagLen; |
73 | |
74 | if (packet->ver != 1) { |
75 | syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver); |
76 | return -1; |
77 | } |
78 | if (packet->type != 1) { |
79 | syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type); |
80 | return -1; |
81 | } |
82 | |
83 | /* Do some sanity checks on packet */ |
84 | if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */ |
85 | syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len); |
86 | return -1; |
87 | } |
88 | |
89 | /* Step through the tags */ |
90 | curTag = packet->payload; |
91 | while(curTag - packet->payload < len) { |
92 | /* Alignment is not guaranteed, so do this by hand... */ |
93 | tagType = (((UINT16_t) curTag[0]) << 8) + |
94 | (UINT16_t) curTag[1]; |
95 | tagLen = (((UINT16_t) curTag[2]) << 8) + |
96 | (UINT16_t) curTag[3]; |
97 | if (tagType == TAG_END_OF_LIST) { |
98 | return 0; |
99 | } |
100 | if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) { |
101 | syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen); |
102 | return -1; |
103 | } |
104 | func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra); |
105 | curTag = curTag + TAG_HDR_SIZE + tagLen; |
106 | } |
107 | return 0; |
108 | } |
109 | |
110 | /********************************************************************** |
111 | *%FUNCTION: findTag |
112 | *%ARGUMENTS: |
113 | * packet -- the PPPoE discovery packet to parse |
114 | * type -- the type of the tag to look for |
115 | * tag -- will be filled in with tag contents |
116 | *%RETURNS: |
117 | * A pointer to the tag if one of the specified type is found; NULL |
118 | * otherwise. |
119 | *%DESCRIPTION: |
120 | * Looks for a specific tag type. |
121 | ***********************************************************************/ |
122 | unsigned char * |
123 | findTag(PPPoEPacket *packet, UINT16_t type, PPPoETag *tag) |
124 | { |
125 | UINT16_t len = ntohs(packet->length); |
126 | unsigned char *curTag; |
127 | UINT16_t tagType, tagLen; |
128 | |
129 | if (packet->ver != 1) { |
130 | syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver); |
131 | return NULL; |
132 | } |
133 | if (packet->type != 1) { |
134 | syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type); |
135 | return NULL; |
136 | } |
137 | |
138 | /* Do some sanity checks on packet */ |
139 | if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */ |
140 | syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len); |
141 | return NULL; |
142 | } |
143 | |
144 | /* Step through the tags */ |
145 | curTag = packet->payload; |
146 | while(curTag - packet->payload < len) { |
147 | /* Alignment is not guaranteed, so do this by hand... */ |
148 | tagType = (((UINT16_t) curTag[0]) << 8) + |
149 | (UINT16_t) curTag[1]; |
150 | tagLen = (((UINT16_t) curTag[2]) << 8) + |
151 | (UINT16_t) curTag[3]; |
152 | if (tagType == TAG_END_OF_LIST) { |
153 | return NULL; |
154 | } |
155 | if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) { |
156 | syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen); |
157 | return NULL; |
158 | } |
159 | if (tagType == type) { |
160 | memcpy(tag, curTag, tagLen + TAG_HDR_SIZE); |
161 | return curTag; |
162 | } |
163 | curTag = curTag + TAG_HDR_SIZE + tagLen; |
164 | } |
165 | return NULL; |
166 | } |
167 | |
168 | /********************************************************************** |
169 | *%FUNCTION: switchToRealID |
170 | *%ARGUMENTS: |
171 | * None |
172 | *%RETURNS: |
173 | * Nothing |
174 | *%DESCRIPTION: |
175 | * Sets effective user-ID and group-ID to real ones. Aborts on failure |
176 | ***********************************************************************/ |
177 | void |
178 | switchToRealID (void) { |
179 | if (IsSetID) { |
180 | if ((int)saved_uid < 0) saved_uid = geteuid(); |
181 | if ((int)saved_gid < 0) saved_gid = getegid(); |
182 | if (setegid(getgid()) < 0) { |
183 | printErr("setgid failed"); |
184 | exit(EXIT_FAILURE); |
185 | } |
186 | if (seteuid(getuid()) < 0) { |
187 | printErr("seteuid failed"); |
188 | exit(EXIT_FAILURE); |
189 | } |
190 | } |
191 | } |
192 | |
193 | /********************************************************************** |
194 | *%FUNCTION: switchToEffectiveID |
195 | *%ARGUMENTS: |
196 | * None |
197 | *%RETURNS: |
198 | * Nothing |
199 | *%DESCRIPTION: |
200 | * Sets effective user-ID and group-ID back to saved gid/uid |
201 | ***********************************************************************/ |
202 | void |
203 | switchToEffectiveID (void) { |
204 | if (IsSetID) { |
205 | if (setegid(saved_gid) < 0) { |
206 | printErr("setgid failed"); |
207 | exit(EXIT_FAILURE); |
208 | } |
209 | if (seteuid(saved_uid) < 0) { |
210 | printErr("seteuid failed"); |
211 | exit(EXIT_FAILURE); |
212 | } |
213 | } |
214 | } |
215 | |
216 | /********************************************************************** |
217 | *%FUNCTION: dropPrivs |
218 | *%ARGUMENTS: |
219 | * None |
220 | *%RETURNS: |
221 | * Nothing |
222 | *%DESCRIPTION: |
223 | * If effective ID is root, try to become "nobody". If that fails and |
224 | * we're SUID, switch to real user-ID |
225 | ***********************************************************************/ |
226 | void |
227 | dropPrivs(void) |
228 | { |
229 | struct passwd *pw = NULL; |
230 | int ok = 0; |
231 | if (geteuid() == 0) { |
232 | pw = getpwnam("nobody"); |
233 | if (pw) { |
234 | if (setgid(pw->pw_gid) < 0) ok++; |
235 | if (setuid(pw->pw_uid) < 0) ok++; |
236 | } |
237 | } |
238 | if (ok < 2 && IsSetID) { |
239 | setegid(getgid()); |
240 | seteuid(getuid()); |
241 | } |
242 | } |
243 | |
244 | /********************************************************************** |
245 | *%FUNCTION: printErr |
246 | *%ARGUMENTS: |
247 | * str -- error message |
248 | *%RETURNS: |
249 | * Nothing |
250 | *%DESCRIPTION: |
251 | * Prints a message to stderr and syslog. |
252 | ***********************************************************************/ |
253 | void |
254 | printErr(char const *str) |
255 | { |
256 | syslog(LOG_ERR, "%s", str); |
257 | } |
258 | |
259 | |
260 | /********************************************************************** |
261 | *%FUNCTION: strDup |
262 | *%ARGUMENTS: |
263 | * str -- string to copy |
264 | *%RETURNS: |
265 | * A malloc'd copy of str. Exits if malloc fails. |
266 | ***********************************************************************/ |
267 | char * |
268 | strDup(char const *str) |
269 | { |
270 | char *copy = malloc(strlen(str)+1); |
271 | if (!copy) { |
272 | rp_fatal("strdup failed"); |
273 | } |
274 | strcpy(copy, str); |
275 | return copy; |
276 | } |
277 | |
278 | /********************************************************************** |
279 | *%FUNCTION: computeTCPChecksum |
280 | *%ARGUMENTS: |
281 | * ipHdr -- pointer to IP header |
282 | * tcpHdr -- pointer to TCP header |
283 | *%RETURNS: |
284 | * The computed TCP checksum |
285 | ***********************************************************************/ |
286 | UINT16_t |
287 | computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr) |
288 | { |
289 | UINT32_t sum = 0; |
290 | UINT16_t count = ipHdr[2] * 256 + ipHdr[3]; |
291 | UINT16_t tmp; |
292 | |
293 | unsigned char *addr = tcpHdr; |
294 | unsigned char pseudoHeader[12]; |
295 | |
296 | /* Count number of bytes in TCP header and data */ |
297 | count -= (ipHdr[0] & 0x0F) * 4; |
298 | |
299 | memcpy(pseudoHeader, ipHdr+12, 8); |
300 | pseudoHeader[8] = 0; |
301 | pseudoHeader[9] = ipHdr[9]; |
302 | pseudoHeader[10] = (count >> 8) & 0xFF; |
303 | pseudoHeader[11] = (count & 0xFF); |
304 | |
305 | /* Checksum the pseudo-header */ |
306 | sum += * (UINT16_t *) pseudoHeader; |
307 | sum += * ((UINT16_t *) (pseudoHeader+2)); |
308 | sum += * ((UINT16_t *) (pseudoHeader+4)); |
309 | sum += * ((UINT16_t *) (pseudoHeader+6)); |
310 | sum += * ((UINT16_t *) (pseudoHeader+8)); |
311 | sum += * ((UINT16_t *) (pseudoHeader+10)); |
312 | |
313 | /* Checksum the TCP header and data */ |
314 | while (count > 1) { |
315 | memcpy(&tmp, addr, sizeof(tmp)); |
316 | sum += (UINT32_t) tmp; |
317 | addr += sizeof(tmp); |
318 | count -= sizeof(tmp); |
319 | } |
320 | if (count > 0) { |
321 | sum += (unsigned char) *addr; |
322 | } |
323 | |
324 | while(sum >> 16) { |
325 | sum = (sum & 0xffff) + (sum >> 16); |
326 | } |
327 | return (UINT16_t) ((~sum) & 0xFFFF); |
328 | } |
329 | |
330 | /********************************************************************** |
331 | *%FUNCTION: clampMSS |
332 | *%ARGUMENTS: |
333 | * packet -- PPPoE session packet |
334 | * dir -- either "incoming" or "outgoing" |
335 | * clampMss -- clamp value |
336 | *%RETURNS: |
337 | * Nothing |
338 | *%DESCRIPTION: |
339 | * Clamps MSS option if TCP SYN flag is set. |
340 | ***********************************************************************/ |
341 | void |
342 | clampMSS(PPPoEPacket *packet, char const *dir, int clampMss) |
343 | { |
344 | unsigned char *tcpHdr; |
345 | unsigned char *ipHdr; |
346 | unsigned char *opt; |
347 | unsigned char *endHdr; |
348 | unsigned char *mssopt = NULL; |
349 | UINT16_t csum; |
350 | |
351 | int len, minlen; |
352 | |
353 | /* check PPP protocol type */ |
354 | if (packet->payload[0] & 0x01) { |
355 | /* 8 bit protocol type */ |
356 | |
357 | /* Is it IPv4? */ |
358 | if (packet->payload[0] != 0x21) { |
359 | /* Nope, ignore it */ |
360 | return; |
361 | } |
362 | |
363 | ipHdr = packet->payload + 1; |
364 | minlen = 41; |
365 | } else { |
366 | /* 16 bit protocol type */ |
367 | |
368 | /* Is it IPv4? */ |
369 | if (packet->payload[0] != 0x00 || |
370 | packet->payload[1] != 0x21) { |
371 | /* Nope, ignore it */ |
372 | return; |
373 | } |
374 | |
375 | ipHdr = packet->payload + 2; |
376 | minlen = 42; |
377 | } |
378 | |
379 | /* Is it too short? */ |
380 | len = (int) ntohs(packet->length); |
381 | if (len < minlen) { |
382 | /* 20 byte IP header; 20 byte TCP header; at least 1 or 2 byte PPP protocol */ |
383 | return; |
384 | } |
385 | |
386 | /* Verify once more that it's IPv4 */ |
387 | if ((ipHdr[0] & 0xF0) != 0x40) { |
388 | return; |
389 | } |
390 | |
391 | /* Is it a fragment that's not at the beginning of the packet? */ |
392 | if ((ipHdr[6] & 0x1F) || ipHdr[7]) { |
393 | /* Yup, don't touch! */ |
394 | return; |
395 | } |
396 | /* Is it TCP? */ |
397 | if (ipHdr[9] != 0x06) { |
398 | return; |
399 | } |
400 | |
401 | /* Get start of TCP header */ |
402 | tcpHdr = ipHdr + (ipHdr[0] & 0x0F) * 4; |
403 | |
404 | /* Is SYN set? */ |
405 | if (!(tcpHdr[13] & 0x02)) { |
406 | return; |
407 | } |
408 | |
409 | /* Compute and verify TCP checksum -- do not touch a packet with a bad |
410 | checksum */ |
411 | csum = computeTCPChecksum(ipHdr, tcpHdr); |
412 | if (csum) { |
413 | syslog(LOG_ERR, "Bad TCP checksum %x", (unsigned int) csum); |
414 | |
415 | /* Upper layers will drop it */ |
416 | return; |
417 | } |
418 | |
419 | /* Look for existing MSS option */ |
420 | endHdr = tcpHdr + ((tcpHdr[12] & 0xF0) >> 2); |
421 | opt = tcpHdr + 20; |
422 | while (opt < endHdr) { |
423 | if (!*opt) break; /* End of options */ |
424 | switch(*opt) { |
425 | case 1: |
426 | opt++; |
427 | break; |
428 | |
429 | case 2: |
430 | if (opt[1] != 4) { |
431 | /* Something fishy about MSS option length. */ |
432 | syslog(LOG_ERR, |
433 | "Bogus length for MSS option (%u) from %u.%u.%u.%u", |
434 | (unsigned int) opt[1], |
435 | (unsigned int) ipHdr[12], |
436 | (unsigned int) ipHdr[13], |
437 | (unsigned int) ipHdr[14], |
438 | (unsigned int) ipHdr[15]); |
439 | return; |
440 | } |
441 | mssopt = opt; |
442 | break; |
443 | default: |
444 | if (opt[1] < 2) { |
445 | /* Someone's trying to attack us? */ |
446 | syslog(LOG_ERR, |
447 | "Bogus TCP option length (%u) from %u.%u.%u.%u", |
448 | (unsigned int) opt[1], |
449 | (unsigned int) ipHdr[12], |
450 | (unsigned int) ipHdr[13], |
451 | (unsigned int) ipHdr[14], |
452 | (unsigned int) ipHdr[15]); |
453 | return; |
454 | } |
455 | opt += (opt[1]); |
456 | break; |
457 | } |
458 | /* Found existing MSS option? */ |
459 | if (mssopt) break; |
460 | } |
461 | |
462 | /* If MSS exists and it's low enough, do nothing */ |
463 | if (mssopt) { |
464 | unsigned mss = mssopt[2] * 256 + mssopt[3]; |
465 | if (mss <= (unsigned int)clampMss) { |
466 | return; |
467 | } |
468 | |
469 | mssopt[2] = (((unsigned) clampMss) >> 8) & 0xFF; |
470 | mssopt[3] = ((unsigned) clampMss) & 0xFF; |
471 | } else { |
472 | /* No MSS option. Don't add one; we'll have to use 536. */ |
473 | return; |
474 | } |
475 | |
476 | /* Recompute TCP checksum */ |
477 | tcpHdr[16] = 0; |
478 | tcpHdr[17] = 0; |
479 | csum = computeTCPChecksum(ipHdr, tcpHdr); |
480 | (* (UINT16_t *) (tcpHdr+16)) = csum; |
481 | } |
482 | |
483 | /*********************************************************************** |
484 | *%FUNCTION: sendPADT |
485 | *%ARGUMENTS: |
486 | * conn -- PPPoE connection |
487 | * msg -- if non-NULL, extra error message to include in PADT packet. |
488 | *%RETURNS: |
489 | * Nothing |
490 | *%DESCRIPTION: |
491 | * Sends a PADT packet |
492 | ***********************************************************************/ |
493 | void |
494 | sendPADT(PPPoEConnection *conn, char const *msg) |
495 | { |
496 | PPPoEPacket packet; |
497 | unsigned char *cursor = packet.payload; |
498 | |
499 | UINT16_t plen = 0; |
500 | |
501 | /* Do nothing if no session established yet */ |
502 | if (!conn->session) return; |
503 | |
504 | /* Do nothing if no discovery socket */ |
505 | if (conn->discoverySocket < 0) return; |
506 | |
507 | memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN); |
508 | memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN); |
509 | |
510 | packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery); |
511 | packet.ver = 1; |
512 | packet.type = 1; |
513 | packet.code = CODE_PADT; |
514 | packet.session = conn->session; |
515 | |
516 | /* Reset Session to zero so there is no possibility of |
517 | recursive calls to this function by any signal handler */ |
518 | conn->session = 0; |
519 | |
520 | /* If we're using Host-Uniq, copy it over */ |
521 | if (conn->useHostUniq) { |
522 | PPPoETag hostUniq; |
523 | pid_t pid = getpid(); |
524 | hostUniq.type = htons(TAG_HOST_UNIQ); |
525 | hostUniq.length = htons(sizeof(pid)); |
526 | memcpy(hostUniq.payload, &pid, sizeof(pid)); |
527 | memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE); |
528 | cursor += sizeof(pid) + TAG_HDR_SIZE; |
529 | plen += sizeof(pid) + TAG_HDR_SIZE; |
530 | } |
531 | |
532 | /* Copy error message */ |
533 | if (msg) { |
534 | PPPoETag err; |
535 | size_t elen = strlen(msg); |
536 | err.type = htons(TAG_GENERIC_ERROR); |
537 | err.length = htons(elen); |
538 | strcpy((char *) err.payload, msg); |
539 | memcpy(cursor, &err, elen + TAG_HDR_SIZE); |
540 | cursor += elen + TAG_HDR_SIZE; |
541 | plen += elen + TAG_HDR_SIZE; |
542 | } |
543 | |
544 | /* Copy cookie and relay-ID if needed */ |
545 | if (conn->cookie.type) { |
546 | CHECK_ROOM(cursor, packet.payload, |
547 | ntohs(conn->cookie.length) + TAG_HDR_SIZE); |
548 | memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE); |
549 | cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE; |
550 | plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE; |
551 | } |
552 | |
553 | if (conn->relayId.type) { |
554 | CHECK_ROOM(cursor, packet.payload, |
555 | ntohs(conn->relayId.length) + TAG_HDR_SIZE); |
556 | memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE); |
557 | cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE; |
558 | plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE; |
559 | } |
560 | |
561 | packet.length = htons(plen); |
562 | sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE)); |
563 | #ifdef DEBUGGING_ENABLED |
564 | if (conn->debugFile) { |
565 | dumpPacket(conn->debugFile, &packet, "SENT"); |
566 | fprintf(conn->debugFile, "\n"); |
567 | fflush(conn->debugFile); |
568 | } |
569 | #endif |
570 | syslog(LOG_INFO,"Sent PADT"); |
571 | } |
572 | |
573 | |
574 | int |
575 | getRawSocket(char const *ifname) |
576 | { |
577 | int ret; |
578 | int optval=1; |
579 | int fd; |
580 | struct ifreq ifr; |
581 | int domain, stype; |
582 | |
583 | struct sockaddr_ll sa; |
584 | |
585 | memset(&sa, 0, sizeof(sa)); |
586 | |
587 | domain = PF_PACKET; |
588 | stype = SOCK_RAW; |
589 | |
590 | fd = socket(domain, stype, htons(ETH_PPPOE_DISCOVERY)); |
591 | if (fd < 0) { |
592 | syslog(LOG_INFO,"failed to create raw socket"); |
593 | return -1; |
594 | } |
595 | |
596 | ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)); |
597 | if (ret < 0) { |
598 | syslog(LOG_INFO,"failed to setsockopt"); |
599 | return -1; |
600 | } |
601 | |
602 | |
603 | /* Get interface index */ |
604 | sa.sll_family = AF_PACKET; |
605 | sa.sll_protocol = htons(ETH_PPPOE_DISCOVERY); |
606 | |
607 | strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
608 | ret = ioctl(fd, SIOCGIFINDEX, &ifr); |
609 | if (ret < 0) { |
610 | syslog(LOG_INFO,"failed to ioctl"); |
611 | return -1; |
612 | } |
613 | sa.sll_ifindex = ifr.ifr_ifindex; |
614 | |
615 | /* We're only interested in packets on specified interface */ |
616 | ret = bind(fd, (struct sockaddr *) &sa, sizeof(sa)); |
617 | if (ret < 0) { |
618 | syslog(LOG_INFO,"failed to bind"); |
619 | return -1; |
620 | } |
621 | |
622 | return fd; |
623 | } |
624 | |
625 | |
626 | void |
627 | sendSavedPADT(char *padt_file) |
628 | { |
629 | FILE *file_fd = NULL; |
630 | char *packet; |
631 | long len; |
632 | int fd; |
633 | |
634 | file_fd = fopen(padt_file, "r"); |
635 | if (!file_fd) { |
636 | syslog(LOG_INFO,"failed to read padt"); |
637 | return; |
638 | } |
639 | |
640 | fseek(file_fd, 0, SEEK_END); |
641 | len = ftell(file_fd); |
642 | if (len < 0) { |
643 | goto free_file_fd; |
644 | } |
645 | else if (len == 0) { |
646 | syslog(LOG_INFO, "sendSavedPADT: file(%s) is a empty file\n", padt_file); |
647 | fclose(file_fd); |
648 | unlink(padt_file); |
649 | return; |
650 | } |
651 | |
652 | packet = malloc(len); |
653 | if (!packet){ |
654 | syslog(LOG_INFO, "sendSavedPADT: failed to malloc"); |
655 | goto free_file_fd; |
656 | } |
657 | |
658 | fseek(file_fd, 0, SEEK_SET); |
659 | fread(packet, 1, len, file_fd); |
660 | |
661 | fd = getRawSocket("eth0"); |
662 | if ( fd < 0){ |
663 | syslog(LOG_INFO, "sendSavedPADT: failed to getRawSocket"); |
664 | goto free_packet; |
665 | |
666 | } |
667 | send( fd, packet, len, 0); |
668 | syslog(LOG_INFO, "Send SavedPADT(fd = %d) by eth0", fd); |
669 | |
670 | close(fd); |
671 | |
672 | free_packet: |
673 | free(packet); |
674 | |
675 | free_file_fd: |
676 | fclose(file_fd); |
677 | } |
678 | |
679 | |
680 | void |
681 | savePADT(PPPoEConnection *conn, char const *msg) |
682 | { |
683 | FILE *padt_file_bin = NULL; |
684 | PPPoEPacket packet; |
685 | unsigned char *cursor = packet.payload; |
686 | |
687 | UINT16_t plen = 0; |
688 | |
689 | memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN); |
690 | memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN); |
691 | |
692 | packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery); |
693 | packet.ver = 1; |
694 | packet.type = 1; |
695 | packet.code = CODE_PADT; |
696 | packet.session = conn->session; |
697 | |
698 | /* Reset Session to zero so there is no possibility of |
699 | recursive calls to this function by any signal handler */ |
700 | //conn->session = 0; |
701 | |
702 | /* If we're using Host-Uniq, copy it over */ |
703 | if (conn->useHostUniq) { |
704 | PPPoETag hostUniq; |
705 | pid_t pid = getpid(); |
706 | hostUniq.type = htons(TAG_HOST_UNIQ); |
707 | hostUniq.length = htons(sizeof(pid)); |
708 | memcpy(hostUniq.payload, &pid, sizeof(pid)); |
709 | memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE); |
710 | cursor += sizeof(pid) + TAG_HDR_SIZE; |
711 | plen += sizeof(pid) + TAG_HDR_SIZE; |
712 | } |
713 | |
714 | /* Copy error message */ |
715 | if (msg) { |
716 | PPPoETag err; |
717 | size_t elen = strlen(msg); |
718 | err.type = htons(TAG_GENERIC_ERROR); |
719 | err.length = htons(elen); |
720 | strcpy((char *) err.payload, msg); |
721 | memcpy(cursor, &err, elen + TAG_HDR_SIZE); |
722 | cursor += elen + TAG_HDR_SIZE; |
723 | plen += elen + TAG_HDR_SIZE; |
724 | } |
725 | |
726 | packet.length = htons(plen); |
727 | |
728 | padt_file_bin = fopen(_ROOT_PATH "/etc/ppp/padt_bin", "w"); |
729 | if (!padt_file_bin) { |
730 | syslog(LOG_INFO,"failed to save padt_bin"); |
731 | } |
732 | fwrite(&packet, (int) (plen + HDR_SIZE), 1, padt_file_bin); |
733 | fflush(padt_file_bin); |
734 | fclose(padt_file_bin); |
735 | } |
736 | |
737 | /*********************************************************************** |
738 | *%FUNCTION: sendPADTf |
739 | *%ARGUMENTS: |
740 | * conn -- PPPoE connection |
741 | * msg -- printf-style format string |
742 | * args -- arguments for msg |
743 | *%RETURNS: |
744 | * Nothing |
745 | *%DESCRIPTION: |
746 | * Sends a PADT packet with a formatted message |
747 | ***********************************************************************/ |
748 | void |
749 | sendPADTf(PPPoEConnection *conn, char const *fmt, ...) |
750 | { |
751 | char msg[512]; |
752 | va_list ap; |
753 | |
754 | va_start(ap, fmt); |
755 | vsnprintf(msg, sizeof(msg), fmt, ap); |
756 | va_end(ap); |
757 | msg[511] = 0; |
758 | |
759 | sendPADT(conn, msg); |
760 | } |
761 | |
762 | /********************************************************************** |
763 | *%FUNCTION: pktLogErrs |
764 | *%ARGUMENTS: |
765 | * pkt -- packet type (a string) |
766 | * type -- tag type |
767 | * len -- tag length |
768 | * data -- tag data |
769 | * extra -- extra user data |
770 | *%RETURNS: |
771 | * Nothing |
772 | *%DESCRIPTION: |
773 | * Logs error tags |
774 | ***********************************************************************/ |
775 | void |
776 | pktLogErrs(char const *pkt, |
777 | UINT16_t type, UINT16_t len, unsigned char *data, |
778 | void *extra) |
779 | { |
780 | char const *str; |
781 | char const *fmt = "%s: %s: %.*s"; |
782 | switch(type) { |
783 | case TAG_SERVICE_NAME_ERROR: |
784 | str = "Service-Name-Error"; |
785 | break; |
786 | case TAG_AC_SYSTEM_ERROR: |
787 | str = "System-Error"; |
788 | break; |
789 | default: |
790 | str = "Generic-Error"; |
791 | } |
792 | |
793 | syslog(LOG_ERR, fmt, pkt, str, (int) len, data); |
794 | fprintf(stderr, fmt, pkt, str, (int) len, data); |
795 | fprintf(stderr, "\n"); |
796 | } |
797 | |
798 | /********************************************************************** |
799 | *%FUNCTION: parseLogErrs |
800 | *%ARGUMENTS: |
801 | * type -- tag type |
802 | * len -- tag length |
803 | * data -- tag data |
804 | * extra -- extra user data |
805 | *%RETURNS: |
806 | * Nothing |
807 | *%DESCRIPTION: |
808 | * Picks error tags out of a packet and logs them. |
809 | ***********************************************************************/ |
810 | void |
811 | parseLogErrs(UINT16_t type, UINT16_t len, unsigned char *data, |
812 | void *extra) |
813 | { |
814 | pktLogErrs("PADT", type, len, data, extra); |
815 | } |
816 |