From: Matteo Croce Date: Sat, 21 Nov 2015 18:45:43 +0100 Subject: [PATCH] pppoe: custom host-uniq tag Add pppoe 'host-uniq' option to set an arbitrary host-uniq tag instead of the pppd pid. Some ISPs use such tag to authenticate the CPE, so it must be set to a proper value to connect. Signed-off-by: Matteo Croce Signed-off-by: Jo-Philipp Wich --- pppd/plugins/rp-pppoe/common.c | 14 ++++----- pppd/plugins/rp-pppoe/discovery.c | 51 +++++++++++++-------------------- pppd/plugins/rp-pppoe/plugin.c | 7 ++++- pppd/plugins/rp-pppoe/pppoe-discovery.c | 38 +++++++++++++++--------- pppd/plugins/rp-pppoe/pppoe.h | 31 +++++++++++++++++++- 5 files changed, 86 insertions(+), 55 deletions(-) diff --git a/pppd/plugins/rp-pppoe/common.c b/pppd/plugins/rp-pppoe/common.c index 89c633c773f9..8f175ece345b 100644 --- a/pppd/plugins/rp-pppoe/common.c +++ b/pppd/plugins/rp-pppoe/common.c @@ -119,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 */ diff --git a/pppd/plugins/rp-pppoe/discovery.c b/pppd/plugins/rp-pppoe/discovery.c index 04877cb8295f..5db8d0defc37 100644 --- a/pppd/plugins/rp-pppoe/discovery.c +++ b/pppd/plugins/rp-pppoe/discovery.c @@ -80,13 +80,10 @@ static void parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data, void *extra) { - int *val = (int *) extra; - if (type == TAG_HOST_UNIQ && len == sizeof(pid_t)) { - pid_t tmp; - memcpy(&tmp, data, len); - if (tmp == getpid()) { - *val = 1; - } + PPPoETag *tag = extra; + + if (type == TAG_HOST_UNIQ && len == ntohs(tag->length)) { + tag->length = memcmp(data, tag->payload, len); } } @@ -104,16 +101,16 @@ parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data, static int packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet) { - int forMe = 0; + PPPoETag hostUniq = conn->hostUniq; /* If packet is not directed to our MAC address, forget it */ if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0; /* If we're not using the Host-Unique tag, then accept the packet */ - if (!conn->useHostUniq) return 1; + if (!conn->hostUniq.length) return 1; - parsePacket(packet, parseForHostUniq, &forMe); - return forMe; + parsePacket(packet, parseForHostUniq, &hostUniq); + return !hostUniq.length; } /********************************************************************** @@ -301,16 +298,12 @@ sendPADI(PPPoEConnection *conn) } /* 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)); - CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE); - 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); + CHECK_ROOM(cursor, packet.payload, len + TAG_HDR_SIZE); + memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE); + cursor += len + TAG_HDR_SIZE; + plen += len + TAG_HDR_SIZE; } /* Add our maximum MTU/MRU */ @@ -478,16 +471,12 @@ sendPADR(PPPoEConnection *conn) cursor += namelen + TAG_HDR_SIZE; /* 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)); - CHECK_ROOM(cursor, packet.payload, sizeof(pid)+TAG_HDR_SIZE); - 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); + CHECK_ROOM(cursor, packet.payload, len+TAG_HDR_SIZE); + memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE); + cursor += len + TAG_HDR_SIZE; + plen += len + TAG_HDR_SIZE; } /* Add our maximum MTU/MRU */ diff --git a/pppd/plugins/rp-pppoe/plugin.c b/pppd/plugins/rp-pppoe/plugin.c index c4c85b462afd..1a7e1e1b4e53 100644 --- a/pppd/plugins/rp-pppoe/plugin.c +++ b/pppd/plugins/rp-pppoe/plugin.c @@ -68,6 +68,7 @@ static char *existingSession = NULL; static int printACNames = 0; static char *pppoe_reqd_mac = NULL; unsigned char pppoe_reqd_mac_addr[6]; +static char *host_uniq = NULL; static int PPPoEDevnameHook(char *cmd, char **argv, int doit); static option_t Options[] = { @@ -85,6 +86,8 @@ static option_t Options[] = { "Be verbose about discovered access concentrators"}, { "pppoe-mac", o_string, &pppoe_reqd_mac, "Only connect to specified MAC address" }, + { "host-uniq", o_string, &host_uniq, + "Specify custom Host-Uniq" }, { NULL } }; int (*OldDevnameHook)(char *cmd, char **argv, int doit) = NULL; @@ -110,7 +113,6 @@ PPPOEInitDevice(void) conn->ifName = devnam; conn->discoverySocket = -1; conn->sessionSocket = -1; - conn->useHostUniq = 1; conn->printACNames = printACNames; conn->discoveryTimeout = PADI_TIMEOUT; return 1; @@ -166,6 +168,9 @@ PPPOEConnectDevice(void) if (lcp_wantoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD) lcp_wantoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD; + if (host_uniq && !parseHostUniq(host_uniq, &conn->hostUniq)) + fatal("Illegal value for host-uniq option"); + conn->acName = acName; conn->serviceName = pppd_pppoe_service; strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam)); diff --git a/pppd/plugins/rp-pppoe/pppoe-discovery.c b/pppd/plugins/rp-pppoe/pppoe-discovery.c index 3d3bf4eecc81..f4f527128c2f 100644 --- a/pppd/plugins/rp-pppoe/pppoe-discovery.c +++ b/pppd/plugins/rp-pppoe/pppoe-discovery.c @@ -347,7 +347,7 @@ packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet) if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0; /* If we're not using the Host-Unique tag, then accept the packet */ - if (!conn->useHostUniq) return 1; + if (!conn->hostUniq.length) return 1; parsePacket(packet, parseForHostUniq, &forMe); return forMe; @@ -473,16 +473,12 @@ sendPADI(PPPoEConnection *conn) cursor += namelen + TAG_HDR_SIZE; /* 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)); - CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE); - 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); + CHECK_ROOM(cursor, packet.payload, len + TAG_HDR_SIZE); + memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE); + cursor += len + TAG_HDR_SIZE; + plen += len + TAG_HDR_SIZE; } packet.length = htons(plen); @@ -644,7 +640,7 @@ int main(int argc, char *argv[]) memset(conn, 0, sizeof(PPPoEConnection)); - while ((opt = getopt(argc, argv, "I:D:VUAS:C:h")) > 0) { + while ((opt = getopt(argc, argv, "I:D:VUW:AS:C:h")) > 0) { switch(opt) { case 'S': conn->serviceName = xstrdup(optarg); @@ -653,7 +649,23 @@ int main(int argc, char *argv[]) conn->acName = xstrdup(optarg); break; case 'U': - conn->useHostUniq = 1; + if(conn->hostUniq.length) { + fprintf(stderr, "-U and -W are mutually exclusive\n"); + exit(EXIT_FAILURE); + } + char pidbuf[5]; + snprintf(pidbuf, sizeof(pidbuf), "%04x", getpid()); + parseHostUniq(pidbuf, &conn->hostUniq); + break; + case 'W': + if(conn->hostUniq.length) { + fprintf(stderr, "-U and -W are mutually exclusive\n"); + exit(EXIT_FAILURE); + } + if (!parseHostUniq(optarg, &conn->hostUniq)) { + fprintf(stderr, "Invalid host-uniq argument: %s\n", optarg); + exit(EXIT_FAILURE); + } break; case 'D': conn->debugFile = fopen(optarg, "w"); diff --git a/pppd/plugins/rp-pppoe/pppoe.h b/pppd/plugins/rp-pppoe/pppoe.h index 9ab2eee3914c..86d2b1e47a25 100644 --- a/pppd/plugins/rp-pppoe/pppoe.h +++ b/pppd/plugins/rp-pppoe/pppoe.h @@ -21,6 +21,8 @@ #include /* For FILE */ #include /* For pid_t */ +#include +#include /* How do we access raw Ethernet devices? */ #undef USE_LINUX_PACKET @@ -235,7 +237,7 @@ typedef struct PPPoEConnectionStruct { char *serviceName; /* Desired service name, if any */ char *acName; /* Desired AC name, if any */ int synchronous; /* Use synchronous PPP */ - int useHostUniq; /* Use Host-Uniq tag */ + PPPoETag hostUniq; /* Use Host-Uniq tag */ int printACNames; /* Just print AC names */ FILE *debugFile; /* Debug file for dumping packets */ int numPADOs; /* Number of PADO packets received */ @@ -291,6 +293,33 @@ void pppoe_printpkt(PPPoEPacket *packet, void (*printer)(void *, char *, ...), void *arg); void pppoe_log_packet(const char *prefix, PPPoEPacket *packet); +static inline int parseHostUniq(const char *uniq, PPPoETag *tag) +{ + int i, len = strlen(uniq); + +#define hex(x) \ + (((x) <= '9') ? ((x) - '0') : \ + (((x) <= 'F') ? ((x) - 'A' + 10) : \ + ((x) - 'a' + 10))) + + if (len % 2) + return 0; + + for (i = 0; i < len; i += 2) + { + if (!isxdigit(uniq[i]) || !isxdigit(uniq[i+1])) + return 0; + + tag->payload[i / 2] = (char)(16 * hex(uniq[i]) + hex(uniq[i+1])); + } + +#undef hex + + tag->type = htons(TAG_HOST_UNIQ); + tag->length = htons(len / 2); + return 1; +} + #define SET_STRING(var, val) do { if (var) free(var); var = strDup(val); } while(0); #define CHECK_ROOM(cursor, start, len) \