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 <mcroce@xxxxxxxxxx> Signed-off-by: Jo-Philipp Wich <jow@xxxxxxxxxxx> --- pppd/plugins/rp-pppoe/common.c | 14 +++---- pppd/plugins/rp-pppoe/discovery.c | 52 ++++++++++--------------- pppd/plugins/rp-pppoe/plugin.c | 15 ++++++- pppd/plugins/rp-pppoe/pppoe-discovery.c | 40 ++++++++++++------- pppd/plugins/rp-pppoe/pppoe.h | 31 ++++++++++++++- 5 files changed, 96 insertions(+), 56 deletions(-) diff --git a/pppd/plugins/rp-pppoe/common.c b/pppd/plugins/rp-pppoe/common.c index 89c633c..8f175ec 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 04877cb..16a59f7 100644 --- a/pppd/plugins/rp-pppoe/discovery.c +++ b/pppd/plugins/rp-pppoe/discovery.c @@ -80,14 +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 +100,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 +297,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 +470,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 c89be94..fd5ad0a 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; 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,17 @@ PPPOEConnectDevice(void) if (lcp_wantoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD) lcp_wantoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD; + if (host_uniq) { + if (!parseHostUniq(host_uniq, &conn->hostUniq)) + fatal("Illegal value for host-uniq option"); + } else { + /* if a custom host-uniq is not supplied, use our PID */ + pid_t pid = getpid(); + conn->hostUniq.type = htons(TAG_HOST_UNIQ); + conn->hostUniq.length = htons(sizeof(pid)); + memcpy(conn->hostUniq.payload, &pid, sizeof(pid)); + } + 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 bce71fc..7eed405 100644 --- a/pppd/plugins/rp-pppoe/pppoe-discovery.c +++ b/pppd/plugins/rp-pppoe/pppoe-discovery.c @@ -356,7 +356,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; @@ -494,16 +494,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); @@ -669,7 +665,7 @@ int main(int argc, char *argv[]) conn->discoveryTimeout = PADI_TIMEOUT; conn->discoveryAttempts = MAX_PADI_ATTEMPTS; - while ((opt = getopt(argc, argv, "I:D:VUQS:C:t:a:h")) > 0) { + while ((opt = getopt(argc, argv, "I:D:VUQS:C:W:t:a:h")) > 0) { switch(opt) { case 'S': conn->serviceName = xstrdup(optarg); @@ -696,7 +692,25 @@ int main(int argc, char *argv[]) } break; case 'U': - conn->useHostUniq = 1; + if(conn->hostUniq.length) { + fprintf(stderr, "-U and -W are mutually exclusive\n"); + exit(EXIT_FAILURE); + } else { + pid_t pid = getpid(); + conn->hostUniq.type = htons(TAG_HOST_UNIQ); + conn->hostUniq.length = htons(sizeof(pid)); + memcpy(conn->hostUniq.payload, &pid, sizeof(pid)); + } + 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 813dcf3..863d268 100644 --- a/pppd/plugins/rp-pppoe/pppoe.h +++ b/pppd/plugins/rp-pppoe/pppoe.h @@ -21,6 +21,8 @@ #include <stdio.h> /* For FILE */ #include <sys/types.h> /* For pid_t */ +#include <ctype.h> +#include <string.h> /* How do we access raw Ethernet devices? */ #undef USE_LINUX_PACKET @@ -236,7 +238,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 */ @@ -293,6 +295,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) +{ + unsigned i, len = strlen(uniq); + +#define hex(x) \ + (((x) <= '9') ? ((x) - '0') : \ + (((x) <= 'F') ? ((x) - 'A' + 10) : \ + ((x) - 'a' + 10))) + + if (!len || len & 1) + return 0; + + for (i = 0; i < len; i += 2) + { + if (!isxdigit(uniq[i]) || !isxdigit(uniq[i+1])) + return 0; + + tag->payload[i / 2] = (char)(hex(uniq[i]) << 4 | 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) \ -- 2.19.1