X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fplugins%2Frp-pppoe%2Fcommon.c;h=9ea7fd609c8774aafbaf2cbe9bb6a6d86679b516;hb=b5599f6001d9b024b3a572ab62c92027d94f052f;hp=a39e97af03dda42765a6f3c9a671015307e1b978;hpb=5d490c4106f4a34864c980b925e183cf3bf575e2;p=ppp.git diff --git a/pppd/plugins/rp-pppoe/common.c b/pppd/plugins/rp-pppoe/common.c index a39e97a..9ea7fd6 100644 --- a/pppd/plugins/rp-pppoe/common.c +++ b/pppd/plugins/rp-pppoe/common.c @@ -14,17 +14,16 @@ ***********************************************************************/ static char const RCSID[] = -"$Id: common.c,v 1.2 2004/01/13 04:03:58 paulus Exp $"; +"$Id: common.c,v 1.3 2008/06/09 08:34:23 paulus Exp $"; +#define _GNU_SOURCE 1 #include "pppoe.h" - -#ifdef HAVE_SYSLOG_H -#include -#endif +#include "pppd/pppd.h" #include #include #include +#include /* for LOG_DEBUG */ #ifdef HAVE_UNISTD_H #include @@ -49,34 +48,32 @@ parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra) unsigned char *curTag; UINT16_t tagType, tagLen; - if (packet->ver != 1) { - syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver); + if (PPPOE_VER(packet->vertype) != 1) { + error("Invalid PPPoE version (%d)", PPPOE_VER(packet->vertype)); return -1; } - if (packet->type != 1) { - syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type); + if (PPPOE_TYPE(packet->vertype) != 1) { + error("Invalid PPPoE type (%d)", PPPOE_TYPE(packet->vertype)); return -1; } /* Do some sanity checks on packet */ - if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */ - syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len); + if (len > ETH_JUMBO_LEN - PPPOE_OVERHEAD) { /* 6-byte overhead for PPPoE header */ + error("Invalid PPPoE packet length (%u)", len); return -1; } /* Step through the tags */ curTag = packet->payload; - while(curTag - packet->payload < len) { + while (curTag - packet->payload + TAG_HDR_SIZE <= len) { /* Alignment is not guaranteed, so do this by hand... */ - tagType = (((UINT16_t) curTag[0]) << 8) + - (UINT16_t) curTag[1]; - tagLen = (((UINT16_t) curTag[2]) << 8) + - (UINT16_t) curTag[3]; + tagType = (curTag[0] << 8) + curTag[1]; + tagLen = (curTag[2] << 8) + curTag[3]; if (tagType == TAG_END_OF_LIST) { return 0; } if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) { - syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen); + error("Invalid PPPoE tag length (%u)", tagLen); return -1; } func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra); @@ -85,303 +82,6 @@ parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra) return 0; } -/********************************************************************** -*%FUNCTION: findTag -*%ARGUMENTS: -* packet -- the PPPoE discovery packet to parse -* type -- the type of the tag to look for -* tag -- will be filled in with tag contents -*%RETURNS: -* A pointer to the tag if one of the specified type is found; NULL -* otherwise. -*%DESCRIPTION: -* Looks for a specific tag type. -***********************************************************************/ -unsigned char * -findTag(PPPoEPacket *packet, UINT16_t type, PPPoETag *tag) -{ - UINT16_t len = ntohs(packet->length); - unsigned char *curTag; - UINT16_t tagType, tagLen; - - if (packet->ver != 1) { - syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver); - return NULL; - } - if (packet->type != 1) { - syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type); - return NULL; - } - - /* Do some sanity checks on packet */ - if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */ - syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len); - return NULL; - } - - /* Step through the tags */ - curTag = packet->payload; - while(curTag - packet->payload < len) { - /* Alignment is not guaranteed, so do this by hand... */ - tagType = (((UINT16_t) curTag[0]) << 8) + - (UINT16_t) curTag[1]; - tagLen = (((UINT16_t) curTag[2]) << 8) + - (UINT16_t) curTag[3]; - if (tagType == TAG_END_OF_LIST) { - return NULL; - } - if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) { - syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen); - return NULL; - } - if (tagType == type) { - memcpy(tag, curTag, tagLen + TAG_HDR_SIZE); - return curTag; - } - curTag = curTag + TAG_HDR_SIZE + tagLen; - } - return NULL; -} - -/********************************************************************** -*%FUNCTION: printErr -*%ARGUMENTS: -* str -- error message -*%RETURNS: -* Nothing -*%DESCRIPTION: -* Prints a message to stderr and syslog. -***********************************************************************/ -void -printErr(char const *str) -{ - fprintf(stderr, "pppoe: %s\n", str); - syslog(LOG_ERR, "%s", str); -} - - -/********************************************************************** -*%FUNCTION: strDup -*%ARGUMENTS: -* str -- string to copy -*%RETURNS: -* A malloc'd copy of str. Exits if malloc fails. -***********************************************************************/ -char * -strDup(char const *str) -{ - char *copy = malloc(strlen(str)+1); - if (!copy) { - rp_fatal("strdup failed"); - } - strcpy(copy, str); - return copy; -} - -#ifdef PPPOE_STANDALONE -/********************************************************************** -*%FUNCTION: computeTCPChecksum -*%ARGUMENTS: -* ipHdr -- pointer to IP header -* tcpHdr -- pointer to TCP header -*%RETURNS: -* The computed TCP checksum -***********************************************************************/ -UINT16_t -computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr) -{ - UINT32_t sum = 0; - UINT16_t count = ipHdr[2] * 256 + ipHdr[3]; - unsigned char *addr = tcpHdr; - unsigned char pseudoHeader[12]; - - /* Count number of bytes in TCP header and data */ - count -= (ipHdr[0] & 0x0F) * 4; - - memcpy(pseudoHeader, ipHdr+12, 8); - pseudoHeader[8] = 0; - pseudoHeader[9] = ipHdr[9]; - pseudoHeader[10] = (count >> 8) & 0xFF; - pseudoHeader[11] = (count & 0xFF); - - /* Checksum the pseudo-header */ - sum += * (UINT16_t *) pseudoHeader; - sum += * ((UINT16_t *) (pseudoHeader+2)); - sum += * ((UINT16_t *) (pseudoHeader+4)); - sum += * ((UINT16_t *) (pseudoHeader+6)); - sum += * ((UINT16_t *) (pseudoHeader+8)); - sum += * ((UINT16_t *) (pseudoHeader+10)); - - /* Checksum the TCP header and data */ - while (count > 1) { - sum += * (UINT16_t *) addr; - addr += 2; - count -= 2; - } - if (count > 0) { - sum += *addr; - } - - while(sum >> 16) { - sum = (sum & 0xffff) + (sum >> 16); - } - return (UINT16_t) (~sum & 0xFFFF); -} - -/********************************************************************** -*%FUNCTION: clampMSS -*%ARGUMENTS: -* packet -- PPPoE session packet -* dir -- either "incoming" or "outgoing" -* clampMss -- clamp value -*%RETURNS: -* Nothing -*%DESCRIPTION: -* Clamps MSS option if TCP SYN flag is set. -***********************************************************************/ -void -clampMSS(PPPoEPacket *packet, char const *dir, int clampMss) -{ - unsigned char *tcpHdr; - unsigned char *ipHdr; - unsigned char *opt; - unsigned char *endHdr; - unsigned char *mssopt = NULL; - UINT16_t csum; - - int len, minlen; - - /* check PPP protocol type */ - if (packet->payload[0] & 0x01) { - /* 8 bit protocol type */ - - /* Is it IPv4? */ - if (packet->payload[0] != 0x21) { - /* Nope, ignore it */ - return; - } - - ipHdr = packet->payload + 1; - minlen = 41; - } else { - /* 16 bit protocol type */ - - /* Is it IPv4? */ - if (packet->payload[0] != 0x00 || - packet->payload[1] != 0x21) { - /* Nope, ignore it */ - return; - } - - ipHdr = packet->payload + 2; - minlen = 42; - } - - /* Is it too short? */ - len = (int) ntohs(packet->length); - if (len < minlen) { - /* 20 byte IP header; 20 byte TCP header; at least 1 or 2 byte PPP protocol */ - return; - } - - /* Verify once more that it's IPv4 */ - if ((ipHdr[0] & 0xF0) != 0x40) { - return; - } - - /* Is it a fragment that's not at the beginning of the packet? */ - if ((ipHdr[6] & 0x1F) || ipHdr[7]) { - /* Yup, don't touch! */ - return; - } - /* Is it TCP? */ - if (ipHdr[9] != 0x06) { - return; - } - - /* Get start of TCP header */ - tcpHdr = ipHdr + (ipHdr[0] & 0x0F) * 4; - - /* Is SYN set? */ - if (!(tcpHdr[13] & 0x02)) { - return; - } - - /* Compute and verify TCP checksum -- do not touch a packet with a bad - checksum */ - csum = computeTCPChecksum(ipHdr, tcpHdr); - if (csum) { - syslog(LOG_ERR, "Bad TCP checksum %x", (unsigned int) csum); - - /* Upper layers will drop it */ - return; - } - - /* Look for existing MSS option */ - endHdr = tcpHdr + ((tcpHdr[12] & 0xF0) >> 2); - opt = tcpHdr + 20; - while (opt < endHdr) { - if (!*opt) break; /* End of options */ - switch(*opt) { - case 1: - opt++; - break; - - case 2: - if (opt[1] != 4) { - /* Something fishy about MSS option length. */ - syslog(LOG_ERR, - "Bogus length for MSS option (%u) from %u.%u.%u.%u", - (unsigned int) opt[1], - (unsigned int) ipHdr[12], - (unsigned int) ipHdr[13], - (unsigned int) ipHdr[14], - (unsigned int) ipHdr[15]); - return; - } - mssopt = opt; - break; - default: - if (opt[1] < 2) { - /* Someone's trying to attack us? */ - syslog(LOG_ERR, - "Bogus TCP option length (%u) from %u.%u.%u.%u", - (unsigned int) opt[1], - (unsigned int) ipHdr[12], - (unsigned int) ipHdr[13], - (unsigned int) ipHdr[14], - (unsigned int) ipHdr[15]); - return; - } - opt += (opt[1]); - break; - } - /* Found existing MSS option? */ - if (mssopt) break; - } - - /* If MSS exists and it's low enough, do nothing */ - if (mssopt) { - unsigned mss = mssopt[2] * 256 + mssopt[3]; - if (mss <= clampMss) { - return; - } - - mssopt[2] = (((unsigned) clampMss) >> 8) & 0xFF; - mssopt[3] = ((unsigned) clampMss) & 0xFF; - } else { - /* No MSS option. Don't add one; we'll have to use 536. */ - return; - } - - /* Recompute TCP checksum */ - tcpHdr[16] = 0; - tcpHdr[17] = 0; - csum = computeTCPChecksum(ipHdr, tcpHdr); - (* (UINT16_t *) (tcpHdr+16)) = csum; -} -#endif /* PPPOE_STANDALONE */ - /*********************************************************************** *%FUNCTION: sendPADT *%ARGUMENTS: @@ -410,8 +110,7 @@ sendPADT(PPPoEConnection *conn, char const *msg) memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN); packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery); - packet.ver = 1; - packet.type = 1; + packet.vertype = PPPOE_VER_TYPE(1, 1); packet.code = CODE_PADT; packet.session = conn->session; @@ -420,15 +119,11 @@ sendPADT(PPPoEConnection *conn, char const *msg) conn->session = 0; /* If we're using Host-Uniq, copy it over */ - if (conn->useHostUniq) { - PPPoETag hostUniq; - pid_t pid = getpid(); - hostUniq.type = htons(TAG_HOST_UNIQ); - hostUniq.length = htons(sizeof(pid)); - memcpy(hostUniq.payload, &pid, sizeof(pid)); - memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE); - cursor += sizeof(pid) + TAG_HDR_SIZE; - plen += sizeof(pid) + TAG_HDR_SIZE; + if (conn->hostUniq.length) { + int len = ntohs(conn->hostUniq.length); + memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE); + cursor += len + TAG_HDR_SIZE; + plen += len + TAG_HDR_SIZE; } /* Copy error message */ @@ -442,7 +137,7 @@ sendPADT(PPPoEConnection *conn, char const *msg) cursor += elen + TAG_HDR_SIZE; plen += elen + TAG_HDR_SIZE; } - + /* Copy cookie and relay-ID if needed */ if (conn->cookie.type) { CHECK_ROOM(cursor, packet.payload, @@ -462,43 +157,126 @@ sendPADT(PPPoEConnection *conn, char const *msg) packet.length = htons(plen); sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE)); - if (conn->debugFile) { - dumpPacket(conn->debugFile, &packet, "SENT"); - fprintf(conn->debugFile, "\n"); - fflush(conn->debugFile); - } - syslog(LOG_INFO,"Sent PADT"); + info("Sent PADT"); } -/********************************************************************** -*%FUNCTION: parseLogErrs -*%ARGUMENTS: -* type -- tag type -* len -- tag length -* data -- tag data -* extra -- extra user data -*%RETURNS: -* Nothing -*%DESCRIPTION: -* Picks error tags out of a packet and logs them. -***********************************************************************/ -void -parseLogErrs(UINT16_t type, UINT16_t len, unsigned char *data, - void *extra) +#define EH(x) (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5] + +/* Print out a PPPOE packet for debugging */ +void pppoe_printpkt(PPPoEPacket *packet, + void (*printer)(void *, char *, ...), void *arg) { - switch(type) { - case TAG_SERVICE_NAME_ERROR: - syslog(LOG_ERR, "PADT: Service-Name-Error: %.*s", (int) len, data); - fprintf(stderr, "PADT: Service-Name-Error: %.*s\n", (int) len, data); - break; - case TAG_AC_SYSTEM_ERROR: - syslog(LOG_ERR, "PADT: System-Error: %.*s", (int) len, data); - fprintf(stderr, "PADT: System-Error: %.*s\n", (int) len, data); + int len = ntohs(packet->length); + int i, tag, tlen, text; + + switch (ntohs(packet->ethHdr.h_proto)) { + case ETH_PPPOE_DISCOVERY: + printer(arg, "PPPOE Discovery V%dT%d ", PPPOE_VER(packet->vertype), + PPPOE_TYPE(packet->vertype)); + switch (packet->code) { + case CODE_PADI: + printer(arg, "PADI"); + break; + case CODE_PADO: + printer(arg, "PADO"); + break; + case CODE_PADR: + printer(arg, "PADR"); + break; + case CODE_PADS: + printer(arg, "PADS"); + break; + case CODE_PADT: + printer(arg, "PADT"); + break; + default: + printer(arg, "unknown code %x", packet->code); + } + printer(arg, " session 0x%x length %d\n", ntohs(packet->session), len); break; - case TAG_GENERIC_ERROR: - syslog(LOG_ERR, "PADT: Generic-Error: %.*s", (int) len, data); - fprintf(stderr, "PADT: Generic-Error: %.*s\n", (int) len, data); + case ETH_PPPOE_SESSION: + printer(arg, "PPPOE Session V%dT%d", PPPOE_VER(packet->vertype), + PPPOE_TYPE(packet->vertype)); + printer(arg, " code 0x%x session 0x%x length %d\n", packet->code, + ntohs(packet->session), len); break; + default: + printer(arg, "Unknown ethernet frame with proto = 0x%x\n", + ntohs(packet->ethHdr.h_proto)); + } + + printer(arg, " dst %02x:%02x:%02x:%02x:%02x:%02x ", EH(packet->ethHdr.h_dest)); + printer(arg, " src %02x:%02x:%02x:%02x:%02x:%02x\n", EH(packet->ethHdr.h_source)); + if (ntohs(packet->ethHdr.h_proto) != ETH_PPPOE_DISCOVERY) + return; + + for (i = 0; i + TAG_HDR_SIZE <= len; i += tlen) { + tag = (packet->payload[i] << 8) + packet->payload[i+1]; + tlen = (packet->payload[i+2] << 8) + packet->payload[i+3]; + if (i + tlen + TAG_HDR_SIZE > len) + break; + text = 0; + i += TAG_HDR_SIZE; + printer(arg, " ["); + switch (tag) { + case TAG_END_OF_LIST: + printer(arg, "end-of-list"); + break; + case TAG_SERVICE_NAME: + printer(arg, "service-name"); + text = 1; + break; + case TAG_AC_NAME: + printer(arg, "AC-name"); + text = 1; + break; + case TAG_HOST_UNIQ: + printer(arg, "host-uniq"); + break; + case TAG_AC_COOKIE: + printer(arg, "AC-cookie"); + break; + case TAG_VENDOR_SPECIFIC: + printer(arg, "vendor-specific"); + break; + case TAG_RELAY_SESSION_ID: + printer(arg, "relay-session-id"); + break; + case TAG_PPP_MAX_PAYLOAD: + printer(arg, "PPP-max-payload"); + break; + case TAG_SERVICE_NAME_ERROR: + printer(arg, "service-name-error"); + text = 1; + break; + case TAG_AC_SYSTEM_ERROR: + printer(arg, "AC-system-error"); + text = 1; + break; + case TAG_GENERIC_ERROR: + printer(arg, "generic-error"); + text = 1; + break; + default: + printer(arg, "unknown tag 0x%x", tag); + } + if (tlen) { + if (text) + printer(arg, " %.*v", tlen, &packet->payload[i]); + else if (tlen <= 32) + printer(arg, " %.*B", tlen, &packet->payload[i]); + else + printer(arg, " %.32B... (length %d)", + &packet->payload[i], tlen); + } + printer(arg, "]"); } + printer(arg, "\n"); } +void pppoe_log_packet(const char *prefix, PPPoEPacket *packet) +{ + init_pr_log(prefix, LOG_DEBUG); + pppoe_printpkt(packet, pr_log, NULL); + end_pr_log(); +}