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 ***********************************************************************/ 15 16 #ifdef HAVE_CONFIG_H 17 #include "config.h" 18 #endif 19 20 #define _GNU_SOURCE 1 21 #include "pppoe.h" 22 #include <pppd/pppd.h> 23 24 #include <string.h> 25 #include <errno.h> 26 #include <stdlib.h> 27 #include <syslog.h> /* for LOG_DEBUG */ 28 #include <ctype.h> 29 30 #ifdef HAVE_UNISTD_H 31 #include <unistd.h> 32 #endif 33 34 /********************************************************************** 35 *%FUNCTION: parsePacket 36 *%ARGUMENTS: 37 * packet -- the PPPoE discovery packet to parse 38 * func -- function called for each tag in the packet 39 * extra -- an opaque data pointer supplied to parsing function 40 *%RETURNS: 41 * 0 if everything went well; -1 if there was an error 42 *%DESCRIPTION: 43 * Parses a PPPoE discovery packet, calling "func" for each tag in the packet. 44 * "func" is passed the additional argument "extra". 45 ***********************************************************************/ 46 int 47 parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra) 48 { 49 UINT16_t len = ntohs(packet->length); 50 unsigned char *curTag; 51 UINT16_t tagType, tagLen; 52 53 if (PPPOE_VER(packet->vertype) != 1) { 54 error("Invalid PPPoE version (%d)", PPPOE_VER(packet->vertype)); 55 return -1; 56 } 57 if (PPPOE_TYPE(packet->vertype) != 1) { 58 error("Invalid PPPoE type (%d)", PPPOE_TYPE(packet->vertype)); 59 return -1; 60 } 61 62 /* Do some sanity checks on packet */ 63 if (len > ETH_JUMBO_LEN - PPPOE_OVERHEAD) { /* 6-byte overhead for PPPoE header */ 64 error("Invalid PPPoE packet length (%u)", len); 65 return -1; 66 } 67 68 /* Step through the tags */ 69 curTag = packet->payload; 70 while (curTag - packet->payload + TAG_HDR_SIZE <= len) { 71 /* Alignment is not guaranteed, so do this by hand... */ 72 tagType = (curTag[0] << 8) + curTag[1]; 73 tagLen = (curTag[2] << 8) + curTag[3]; 74 if (tagType == TAG_END_OF_LIST) { 75 return 0; 76 } 77 if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) { 78 error("Invalid PPPoE tag length (%u)", tagLen); 79 return -1; 80 } 81 func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra); 82 curTag = curTag + TAG_HDR_SIZE + tagLen; 83 } 84 return 0; 85 } 86 87 /*********************************************************************** 88 *%FUNCTION: sendPADT 89 *%ARGUMENTS: 90 * conn -- PPPoE connection 91 * msg -- if non-NULL, extra error message to include in PADT packet. 92 *%RETURNS: 93 * Nothing 94 *%DESCRIPTION: 95 * Sends a PADT packet 96 ***********************************************************************/ 97 void 98 sendPADT(PPPoEConnection *conn, char const *msg) 99 { 100 PPPoEPacket packet; 101 unsigned char *cursor = packet.payload; 102 103 UINT16_t plen = 0; 104 105 /* Do nothing if no session established yet */ 106 if (!conn->session) return; 107 108 /* Do nothing if no discovery socket */ 109 if (conn->discoverySocket < 0) return; 110 111 memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN); 112 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN); 113 114 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery); 115 packet.vertype = PPPOE_VER_TYPE(1, 1); 116 packet.code = CODE_PADT; 117 packet.session = conn->session; 118 119 /* Reset Session to zero so there is no possibility of 120 recursive calls to this function by any signal handler */ 121 conn->session = 0; 122 123 /* If we're using Host-Uniq, copy it over */ 124 if (conn->hostUniq.length) { 125 int len = ntohs(conn->hostUniq.length); 126 memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE); 127 cursor += len + TAG_HDR_SIZE; 128 plen += len + TAG_HDR_SIZE; 129 } 130 131 /* Copy error message */ 132 if (msg) { 133 PPPoETag err; 134 size_t elen = strlen(msg); 135 err.type = htons(TAG_GENERIC_ERROR); 136 err.length = htons(elen); 137 strcpy((char*) err.payload, msg); 138 memcpy(cursor, &err, elen + TAG_HDR_SIZE); 139 cursor += elen + TAG_HDR_SIZE; 140 plen += elen + TAG_HDR_SIZE; 141 } 142 143 /* Copy cookie and relay-ID if needed */ 144 if (conn->cookie.type) { 145 CHECK_ROOM(cursor, packet.payload, 146 ntohs(conn->cookie.length) + TAG_HDR_SIZE); 147 memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE); 148 cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE; 149 plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE; 150 } 151 152 if (conn->relayId.type) { 153 CHECK_ROOM(cursor, packet.payload, 154 ntohs(conn->relayId.length) + TAG_HDR_SIZE); 155 memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE); 156 cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE; 157 plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE; 158 } 159 160 packet.length = htons(plen); 161 sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE)); 162 info("Sent PADT"); 163 } 164 165 static void 166 pppoe_printpkt_hex(void (*printer)(void *, char *, ...), void *arg, unsigned char const *buf, int len) 167 { 168 int i; 169 int base; 170 171 /* do NOT dump PAP packets */ 172 if (len >= 2 && buf[0] == 0xC0 && buf[1] == 0x23) { 173 printer(arg, "(PAP Authentication Frame -- Contents not dumped)\n"); 174 return; 175 } 176 177 for (base=0; base<len; base += 16) { 178 for (i=base; i<base+16; i++) { 179 if (i < len) { 180 printer(arg, "%02x ", (unsigned) buf[i]); 181 } else { 182 printer(arg, " "); 183 } 184 } 185 printer(arg, " "); 186 for (i=base; i<base+16; i++) { 187 if (i < len) { 188 if (isprint(buf[i])) { 189 printer(arg, "%c", buf[i]); 190 } else { 191 printer(arg, "."); 192 } 193 } else { 194 break; 195 } 196 } 197 printer(arg, "\n"); 198 } 199 } 200 201 #define EH(x) (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5] 202 203 /* Print out a PPPOE packet for debugging */ 204 void pppoe_printpkt(PPPoEPacket *packet, 205 void (*printer)(void *, char *, ...), void *arg) 206 { 207 int len = ntohs(packet->length); 208 int i, j, tag, tlen, text; 209 210 switch (ntohs(packet->ethHdr.h_proto)) { 211 case ETH_PPPOE_DISCOVERY: 212 printer(arg, "PPPOE Discovery V%dT%d ", PPPOE_VER(packet->vertype), 213 PPPOE_TYPE(packet->vertype)); 214 switch (packet->code) { 215 case CODE_PADI: 216 printer(arg, "PADI"); 217 break; 218 case CODE_PADO: 219 printer(arg, "PADO"); 220 break; 221 case CODE_PADR: 222 printer(arg, "PADR"); 223 break; 224 case CODE_PADS: 225 printer(arg, "PADS"); 226 break; 227 case CODE_PADT: 228 printer(arg, "PADT"); 229 break; 230 default: 231 printer(arg, "unknown code %x", packet->code); 232 } 233 printer(arg, " session 0x%x length %d\n", ntohs(packet->session), len); 234 break; 235 case ETH_PPPOE_SESSION: 236 printer(arg, "PPPOE Session V%dT%d", PPPOE_VER(packet->vertype), 237 PPPOE_TYPE(packet->vertype)); 238 printer(arg, " code 0x%x session 0x%x length %d\n", packet->code, 239 ntohs(packet->session), len); 240 break; 241 default: 242 printer(arg, "Unknown ethernet frame with proto = 0x%x\n", 243 ntohs(packet->ethHdr.h_proto)); 244 } 245 246 printer(arg, " dst %02x:%02x:%02x:%02x:%02x:%02x ", EH(packet->ethHdr.h_dest)); 247 printer(arg, " src %02x:%02x:%02x:%02x:%02x:%02x\n", EH(packet->ethHdr.h_source)); 248 if (pppoe_verbose >= 2) 249 pppoe_printpkt_hex(printer, arg, packet->payload, ntohs(packet->length)); 250 if (ntohs(packet->ethHdr.h_proto) != ETH_PPPOE_DISCOVERY) 251 return; 252 253 for (i = 0; i + TAG_HDR_SIZE <= len; i += tlen) { 254 tag = (packet->payload[i] << 8) + packet->payload[i+1]; 255 tlen = (packet->payload[i+2] << 8) + packet->payload[i+3]; 256 if (i + tlen + TAG_HDR_SIZE > len) 257 break; 258 text = 0; 259 i += TAG_HDR_SIZE; 260 printer(arg, " ["); 261 switch (tag) { 262 case TAG_END_OF_LIST: 263 printer(arg, "end-of-list"); 264 break; 265 case TAG_SERVICE_NAME: 266 printer(arg, "service-name"); 267 text = 1; 268 break; 269 case TAG_AC_NAME: 270 printer(arg, "AC-name"); 271 text = 1; 272 break; 273 case TAG_HOST_UNIQ: 274 printer(arg, "host-uniq"); 275 break; 276 case TAG_AC_COOKIE: 277 printer(arg, "AC-cookie"); 278 break; 279 case TAG_VENDOR_SPECIFIC: 280 printer(arg, "vendor-specific"); 281 break; 282 case TAG_RELAY_SESSION_ID: 283 printer(arg, "relay-session-id"); 284 break; 285 case TAG_PPP_MAX_PAYLOAD: 286 printer(arg, "PPP-max-payload"); 287 break; 288 case TAG_SERVICE_NAME_ERROR: 289 printer(arg, "service-name-error"); 290 text = 1; 291 break; 292 case TAG_AC_SYSTEM_ERROR: 293 printer(arg, "AC-system-error"); 294 text = 1; 295 break; 296 case TAG_GENERIC_ERROR: 297 printer(arg, "generic-error"); 298 text = 1; 299 break; 300 default: 301 printer(arg, "unknown tag 0x%x", tag); 302 } 303 if (tlen) { 304 /* If it is supposed to be text, make sure it's all printing chars */ 305 if (text) { 306 for (j = 0; j < tlen; ++j) { 307 if (!isprint(packet->payload[i+j])) { 308 text = 0; 309 break; 310 } 311 } 312 } 313 if (text) 314 printer(arg, " %.*s", tlen, &packet->payload[i]); 315 else { 316 for (j = 0; j < tlen && j < 32; j++) 317 printer(arg, " %02x", (unsigned) *(&packet->payload[i]+j)); 318 if (j < tlen) 319 printer(arg, "... (length %d)", tlen); 320 } 321 } 322 printer(arg, "]"); 323 } 324 printer(arg, "\n"); 325 } 326 327 void pppoe_log_packet(const char *prefix, PPPoEPacket *packet) 328 { 329 init_pr_log(prefix, LOG_DEBUG); 330 pppoe_printpkt(packet, pr_log, NULL); 331 end_pr_log(); 332 } 333