blob: 36f644aeee95bfa44128351ff9bf83175b81975a
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 | fprintf(stderr, "pppoe: %s\n", str); |
257 | syslog(LOG_ERR, "%s", str); |
258 | } |
259 | |
260 | |
261 | /********************************************************************** |
262 | *%FUNCTION: strDup |
263 | *%ARGUMENTS: |
264 | * str -- string to copy |
265 | *%RETURNS: |
266 | * A malloc'd copy of str. Exits if malloc fails. |
267 | ***********************************************************************/ |
268 | char * |
269 | strDup(char const *str) |
270 | { |
271 | char *copy = malloc(strlen(str)+1); |
272 | if (!copy) { |
273 | rp_fatal("strdup failed"); |
274 | } |
275 | strcpy(copy, str); |
276 | return copy; |
277 | } |
278 | |
279 | /********************************************************************** |
280 | *%FUNCTION: computeTCPChecksum |
281 | *%ARGUMENTS: |
282 | * ipHdr -- pointer to IP header |
283 | * tcpHdr -- pointer to TCP header |
284 | *%RETURNS: |
285 | * The computed TCP checksum |
286 | ***********************************************************************/ |
287 | UINT16_t |
288 | computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr) |
289 | { |
290 | UINT32_t sum = 0; |
291 | UINT16_t count = ipHdr[2] * 256 + ipHdr[3]; |
292 | UINT16_t tmp; |
293 | |
294 | unsigned char *addr = tcpHdr; |
295 | unsigned char pseudoHeader[12]; |
296 | |
297 | /* Count number of bytes in TCP header and data */ |
298 | count -= (ipHdr[0] & 0x0F) * 4; |
299 | |
300 | memcpy(pseudoHeader, ipHdr+12, 8); |
301 | pseudoHeader[8] = 0; |
302 | pseudoHeader[9] = ipHdr[9]; |
303 | pseudoHeader[10] = (count >> 8) & 0xFF; |
304 | pseudoHeader[11] = (count & 0xFF); |
305 | |
306 | /* Checksum the pseudo-header */ |
307 | sum += * (UINT16_t *) pseudoHeader; |
308 | sum += * ((UINT16_t *) (pseudoHeader+2)); |
309 | sum += * ((UINT16_t *) (pseudoHeader+4)); |
310 | sum += * ((UINT16_t *) (pseudoHeader+6)); |
311 | sum += * ((UINT16_t *) (pseudoHeader+8)); |
312 | sum += * ((UINT16_t *) (pseudoHeader+10)); |
313 | |
314 | /* Checksum the TCP header and data */ |
315 | while (count > 1) { |
316 | memcpy(&tmp, addr, sizeof(tmp)); |
317 | sum += (UINT32_t) tmp; |
318 | addr += sizeof(tmp); |
319 | count -= sizeof(tmp); |
320 | } |
321 | if (count > 0) { |
322 | sum += (unsigned char) *addr; |
323 | } |
324 | |
325 | while(sum >> 16) { |
326 | sum = (sum & 0xffff) + (sum >> 16); |
327 | } |
328 | return (UINT16_t) ((~sum) & 0xFFFF); |
329 | } |
330 | |
331 | /********************************************************************** |
332 | *%FUNCTION: clampMSS |
333 | *%ARGUMENTS: |
334 | * packet -- PPPoE session packet |
335 | * dir -- either "incoming" or "outgoing" |
336 | * clampMss -- clamp value |
337 | *%RETURNS: |
338 | * Nothing |
339 | *%DESCRIPTION: |
340 | * Clamps MSS option if TCP SYN flag is set. |
341 | ***********************************************************************/ |
342 | void |
343 | clampMSS(PPPoEPacket *packet, char const *dir, int clampMss) |
344 | { |
345 | unsigned char *tcpHdr; |
346 | unsigned char *ipHdr; |
347 | unsigned char *opt; |
348 | unsigned char *endHdr; |
349 | unsigned char *mssopt = NULL; |
350 | UINT16_t csum; |
351 | |
352 | int len, minlen; |
353 | |
354 | /* check PPP protocol type */ |
355 | if (packet->payload[0] & 0x01) { |
356 | /* 8 bit protocol type */ |
357 | |
358 | /* Is it IPv4? */ |
359 | if (packet->payload[0] != 0x21) { |
360 | /* Nope, ignore it */ |
361 | return; |
362 | } |
363 | |
364 | ipHdr = packet->payload + 1; |
365 | minlen = 41; |
366 | } else { |
367 | /* 16 bit protocol type */ |
368 | |
369 | /* Is it IPv4? */ |
370 | if (packet->payload[0] != 0x00 || |
371 | packet->payload[1] != 0x21) { |
372 | /* Nope, ignore it */ |
373 | return; |
374 | } |
375 | |
376 | ipHdr = packet->payload + 2; |
377 | minlen = 42; |
378 | } |
379 | |
380 | /* Is it too short? */ |
381 | len = (int) ntohs(packet->length); |
382 | if (len < minlen) { |
383 | /* 20 byte IP header; 20 byte TCP header; at least 1 or 2 byte PPP protocol */ |
384 | return; |
385 | } |
386 | |
387 | /* Verify once more that it's IPv4 */ |
388 | if ((ipHdr[0] & 0xF0) != 0x40) { |
389 | return; |
390 | } |
391 | |
392 | /* Is it a fragment that's not at the beginning of the packet? */ |
393 | if ((ipHdr[6] & 0x1F) || ipHdr[7]) { |
394 | /* Yup, don't touch! */ |
395 | return; |
396 | } |
397 | /* Is it TCP? */ |
398 | if (ipHdr[9] != 0x06) { |
399 | return; |
400 | } |
401 | |
402 | /* Get start of TCP header */ |
403 | tcpHdr = ipHdr + (ipHdr[0] & 0x0F) * 4; |
404 | |
405 | /* Is SYN set? */ |
406 | if (!(tcpHdr[13] & 0x02)) { |
407 | return; |
408 | } |
409 | |
410 | /* Compute and verify TCP checksum -- do not touch a packet with a bad |
411 | checksum */ |
412 | csum = computeTCPChecksum(ipHdr, tcpHdr); |
413 | if (csum) { |
414 | syslog(LOG_ERR, "Bad TCP checksum %x", (unsigned int) csum); |
415 | |
416 | /* Upper layers will drop it */ |
417 | return; |
418 | } |
419 | |
420 | /* Look for existing MSS option */ |
421 | endHdr = tcpHdr + ((tcpHdr[12] & 0xF0) >> 2); |
422 | opt = tcpHdr + 20; |
423 | while (opt < endHdr) { |
424 | if (!*opt) break; /* End of options */ |
425 | switch(*opt) { |
426 | case 1: |
427 | opt++; |
428 | break; |
429 | |
430 | case 2: |
431 | if (opt[1] != 4) { |
432 | /* Something fishy about MSS option length. */ |
433 | syslog(LOG_ERR, |
434 | "Bogus length for MSS option (%u) from %u.%u.%u.%u", |
435 | (unsigned int) opt[1], |
436 | (unsigned int) ipHdr[12], |
437 | (unsigned int) ipHdr[13], |
438 | (unsigned int) ipHdr[14], |
439 | (unsigned int) ipHdr[15]); |
440 | return; |
441 | } |
442 | mssopt = opt; |
443 | break; |
444 | default: |
445 | if (opt[1] < 2) { |
446 | /* Someone's trying to attack us? */ |
447 | syslog(LOG_ERR, |
448 | "Bogus TCP option length (%u) from %u.%u.%u.%u", |
449 | (unsigned int) opt[1], |
450 | (unsigned int) ipHdr[12], |
451 | (unsigned int) ipHdr[13], |
452 | (unsigned int) ipHdr[14], |
453 | (unsigned int) ipHdr[15]); |
454 | return; |
455 | } |
456 | opt += (opt[1]); |
457 | break; |
458 | } |
459 | /* Found existing MSS option? */ |
460 | if (mssopt) break; |
461 | } |
462 | |
463 | /* If MSS exists and it's low enough, do nothing */ |
464 | if (mssopt) { |
465 | unsigned mss = mssopt[2] * 256 + mssopt[3]; |
466 | if (mss <= (unsigned int)clampMss) { |
467 | return; |
468 | } |
469 | |
470 | mssopt[2] = (((unsigned) clampMss) >> 8) & 0xFF; |
471 | mssopt[3] = ((unsigned) clampMss) & 0xFF; |
472 | } else { |
473 | /* No MSS option. Don't add one; we'll have to use 536. */ |
474 | return; |
475 | } |
476 | |
477 | /* Recompute TCP checksum */ |
478 | tcpHdr[16] = 0; |
479 | tcpHdr[17] = 0; |
480 | csum = computeTCPChecksum(ipHdr, tcpHdr); |
481 | (* (UINT16_t *) (tcpHdr+16)) = csum; |
482 | } |
483 | |
484 | /*********************************************************************** |
485 | *%FUNCTION: sendPADT |
486 | *%ARGUMENTS: |
487 | * conn -- PPPoE connection |
488 | * msg -- if non-NULL, extra error message to include in PADT packet. |
489 | *%RETURNS: |
490 | * Nothing |
491 | *%DESCRIPTION: |
492 | * Sends a PADT packet |
493 | ***********************************************************************/ |
494 | void |
495 | sendPADT(PPPoEConnection *conn, char const *msg) |
496 | { |
497 | PPPoEPacket packet; |
498 | unsigned char *cursor = packet.payload; |
499 | |
500 | UINT16_t plen = 0; |
501 | |
502 | /* Do nothing if no session established yet */ |
503 | if (!conn->session) return; |
504 | |
505 | /* Do nothing if no discovery socket */ |
506 | if (conn->discoverySocket < 0) return; |
507 | |
508 | memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN); |
509 | memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN); |
510 | |
511 | packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery); |
512 | packet.ver = 1; |
513 | packet.type = 1; |
514 | packet.code = CODE_PADT; |
515 | packet.session = conn->session; |
516 | |
517 | /* Reset Session to zero so there is no possibility of |
518 | recursive calls to this function by any signal handler */ |
519 | conn->session = 0; |
520 | |
521 | /* If we're using Host-Uniq, copy it over */ |
522 | if (conn->useHostUniq) { |
523 | PPPoETag hostUniq; |
524 | pid_t pid = getpid(); |
525 | hostUniq.type = htons(TAG_HOST_UNIQ); |
526 | hostUniq.length = htons(sizeof(pid)); |
527 | memcpy(hostUniq.payload, &pid, sizeof(pid)); |
528 | memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE); |
529 | cursor += sizeof(pid) + TAG_HDR_SIZE; |
530 | plen += sizeof(pid) + TAG_HDR_SIZE; |
531 | } |
532 | |
533 | /* Copy error message */ |
534 | if (msg) { |
535 | PPPoETag err; |
536 | size_t elen = strlen(msg); |
537 | err.type = htons(TAG_GENERIC_ERROR); |
538 | err.length = htons(elen); |
539 | strcpy((char *) err.payload, msg); |
540 | memcpy(cursor, &err, elen + TAG_HDR_SIZE); |
541 | cursor += elen + TAG_HDR_SIZE; |
542 | plen += elen + TAG_HDR_SIZE; |
543 | } |
544 | |
545 | /* Copy cookie and relay-ID if needed */ |
546 | if (conn->cookie.type) { |
547 | CHECK_ROOM(cursor, packet.payload, |
548 | ntohs(conn->cookie.length) + TAG_HDR_SIZE); |
549 | memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE); |
550 | cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE; |
551 | plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE; |
552 | } |
553 | |
554 | if (conn->relayId.type) { |
555 | CHECK_ROOM(cursor, packet.payload, |
556 | ntohs(conn->relayId.length) + TAG_HDR_SIZE); |
557 | memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE); |
558 | cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE; |
559 | plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE; |
560 | } |
561 | |
562 | packet.length = htons(plen); |
563 | sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE)); |
564 | #ifdef DEBUGGING_ENABLED |
565 | if (conn->debugFile) { |
566 | dumpPacket(conn->debugFile, &packet, "SENT"); |
567 | fprintf(conn->debugFile, "\n"); |
568 | fflush(conn->debugFile); |
569 | } |
570 | #endif |
571 | syslog(LOG_INFO,"Sent PADT"); |
572 | } |
573 | |
574 | |
575 | int |
576 | getRawSocket(char const *ifname) |
577 | { |
578 | int ret; |
579 | int optval=1; |
580 | int fd; |
581 | struct ifreq ifr; |
582 | int domain, stype; |
583 | |
584 | struct sockaddr_ll sa; |
585 | |
586 | memset(&sa, 0, sizeof(sa)); |
587 | |
588 | domain = PF_PACKET; |
589 | stype = SOCK_RAW; |
590 | |
591 | fd = socket(domain, stype, htons(ETH_PPPOE_DISCOVERY)); |
592 | if (fd < 0) { |
593 | syslog(LOG_INFO,"failed to create raw socket"); |
594 | return -1; |
595 | } |
596 | |
597 | ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)); |
598 | if (ret < 0) { |
599 | syslog(LOG_INFO,"failed to setsockopt"); |
600 | return -1; |
601 | } |
602 | |
603 | |
604 | /* Get interface index */ |
605 | sa.sll_family = AF_PACKET; |
606 | sa.sll_protocol = htons(ETH_PPPOE_DISCOVERY); |
607 | |
608 | strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
609 | ret = ioctl(fd, SIOCGIFINDEX, &ifr); |
610 | if (ret < 0) { |
611 | syslog(LOG_INFO,"failed to ioctl"); |
612 | return -1; |
613 | } |
614 | sa.sll_ifindex = ifr.ifr_ifindex; |
615 | |
616 | /* We're only interested in packets on specified interface */ |
617 | ret = bind(fd, (struct sockaddr *) &sa, sizeof(sa)); |
618 | if (ret < 0) { |
619 | syslog(LOG_INFO,"failed to bind"); |
620 | return -1; |
621 | } |
622 | |
623 | return fd; |
624 | } |
625 | |
626 | |
627 | void |
628 | sendSavedPADT(char *padt_file) |
629 | { |
630 | FILE *file_fd = NULL; |
631 | char *packet; |
632 | long len; |
633 | int fd; |
634 | |
635 | file_fd = fopen(padt_file, "r"); |
636 | if (!file_fd) { |
637 | syslog(LOG_INFO,"failed to read padt"); |
638 | return; |
639 | } |
640 | |
641 | fseek(file_fd, 0, SEEK_END); |
642 | len = ftell(file_fd); |
643 | if (len < 0) { |
644 | goto free_file_fd; |
645 | } |
646 | |
647 | packet = malloc(len); |
648 | if (!packet){ |
649 | syslog(LOG_INFO, "sendSavedPADT: failed to malloc"); |
650 | goto free_file_fd; |
651 | } |
652 | |
653 | fseek(file_fd, 0, SEEK_SET); |
654 | fread(packet, 1, len, file_fd); |
655 | |
656 | fd = getRawSocket("eth0"); |
657 | if ( fd < 0){ |
658 | syslog(LOG_INFO, "sendSavedPADT: failed to getRawSocket"); |
659 | goto free_packet; |
660 | |
661 | } |
662 | send( fd, packet, len, 0); |
663 | syslog(LOG_INFO, "Send SavedPADT(fd = %d) by eth0", fd); |
664 | |
665 | close(fd); |
666 | |
667 | free_packet: |
668 | free(packet); |
669 | |
670 | free_file_fd: |
671 | fclose(file_fd); |
672 | } |
673 | |
674 | |
675 | void |
676 | savePADT(PPPoEConnection *conn, char const *msg) |
677 | { |
678 | FILE *padt_file_bin = NULL; |
679 | PPPoEPacket packet; |
680 | unsigned char *cursor = packet.payload; |
681 | |
682 | UINT16_t plen = 0; |
683 | |
684 | memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN); |
685 | memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN); |
686 | |
687 | packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery); |
688 | packet.ver = 1; |
689 | packet.type = 1; |
690 | packet.code = CODE_PADT; |
691 | packet.session = conn->session; |
692 | |
693 | /* Reset Session to zero so there is no possibility of |
694 | recursive calls to this function by any signal handler */ |
695 | //conn->session = 0; |
696 | |
697 | /* If we're using Host-Uniq, copy it over */ |
698 | if (conn->useHostUniq) { |
699 | PPPoETag hostUniq; |
700 | pid_t pid = getpid(); |
701 | hostUniq.type = htons(TAG_HOST_UNIQ); |
702 | hostUniq.length = htons(sizeof(pid)); |
703 | memcpy(hostUniq.payload, &pid, sizeof(pid)); |
704 | memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE); |
705 | cursor += sizeof(pid) + TAG_HDR_SIZE; |
706 | plen += sizeof(pid) + TAG_HDR_SIZE; |
707 | } |
708 | |
709 | /* Copy error message */ |
710 | if (msg) { |
711 | PPPoETag err; |
712 | size_t elen = strlen(msg); |
713 | err.type = htons(TAG_GENERIC_ERROR); |
714 | err.length = htons(elen); |
715 | strcpy((char *) err.payload, msg); |
716 | memcpy(cursor, &err, elen + TAG_HDR_SIZE); |
717 | cursor += elen + TAG_HDR_SIZE; |
718 | plen += elen + TAG_HDR_SIZE; |
719 | } |
720 | |
721 | packet.length = htons(plen); |
722 | |
723 | padt_file_bin = fopen(_ROOT_PATH "/etc/ppp/padt_bin", "w"); |
724 | if (!padt_file_bin) { |
725 | syslog(LOG_INFO,"failed to save padt_bin"); |
726 | } |
727 | fwrite(&packet, (int) (plen + HDR_SIZE), 1, padt_file_bin); |
728 | fflush(padt_file_bin); |
729 | fclose(padt_file_bin); |
730 | } |
731 | |
732 | /*********************************************************************** |
733 | *%FUNCTION: sendPADTf |
734 | *%ARGUMENTS: |
735 | * conn -- PPPoE connection |
736 | * msg -- printf-style format string |
737 | * args -- arguments for msg |
738 | *%RETURNS: |
739 | * Nothing |
740 | *%DESCRIPTION: |
741 | * Sends a PADT packet with a formatted message |
742 | ***********************************************************************/ |
743 | void |
744 | sendPADTf(PPPoEConnection *conn, char const *fmt, ...) |
745 | { |
746 | char msg[512]; |
747 | va_list ap; |
748 | |
749 | va_start(ap, fmt); |
750 | vsnprintf(msg, sizeof(msg), fmt, ap); |
751 | va_end(ap); |
752 | msg[511] = 0; |
753 | |
754 | sendPADT(conn, msg); |
755 | } |
756 | |
757 | /********************************************************************** |
758 | *%FUNCTION: pktLogErrs |
759 | *%ARGUMENTS: |
760 | * pkt -- packet type (a string) |
761 | * type -- tag type |
762 | * len -- tag length |
763 | * data -- tag data |
764 | * extra -- extra user data |
765 | *%RETURNS: |
766 | * Nothing |
767 | *%DESCRIPTION: |
768 | * Logs error tags |
769 | ***********************************************************************/ |
770 | void |
771 | pktLogErrs(char const *pkt, |
772 | UINT16_t type, UINT16_t len, unsigned char *data, |
773 | void *extra) |
774 | { |
775 | char const *str; |
776 | char const *fmt = "%s: %s: %.*s"; |
777 | switch(type) { |
778 | case TAG_SERVICE_NAME_ERROR: |
779 | str = "Service-Name-Error"; |
780 | break; |
781 | case TAG_AC_SYSTEM_ERROR: |
782 | str = "System-Error"; |
783 | break; |
784 | default: |
785 | str = "Generic-Error"; |
786 | } |
787 | |
788 | syslog(LOG_ERR, fmt, pkt, str, (int) len, data); |
789 | fprintf(stderr, fmt, pkt, str, (int) len, data); |
790 | fprintf(stderr, "\n"); |
791 | } |
792 | |
793 | /********************************************************************** |
794 | *%FUNCTION: parseLogErrs |
795 | *%ARGUMENTS: |
796 | * type -- tag type |
797 | * len -- tag length |
798 | * data -- tag data |
799 | * extra -- extra user data |
800 | *%RETURNS: |
801 | * Nothing |
802 | *%DESCRIPTION: |
803 | * Picks error tags out of a packet and logs them. |
804 | ***********************************************************************/ |
805 | void |
806 | parseLogErrs(UINT16_t type, UINT16_t len, unsigned char *data, |
807 | void *extra) |
808 | { |
809 | pktLogErrs("PADT", type, len, data, extra); |
810 | } |
811 |