pppoe: Custom host-uniq tag
authorMatteo Croce <mcroce@redhat.com>
Sat, 4 May 2019 16:48:53 +0000 (18:48 +0200)
committerPaul Mackerras <paulus@samba.org>
Sat, 18 May 2019 08:22:12 +0000 (18:22 +1000)
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@redhat.com>
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Signed-off-by: Paul Mackerras <paulus@samba.org>
pppd/plugins/rp-pppoe/common.c
pppd/plugins/rp-pppoe/discovery.c
pppd/plugins/rp-pppoe/plugin.c
pppd/plugins/rp-pppoe/pppoe-discovery.c
pppd/plugins/rp-pppoe/pppoe.h

index 89c633c773f93ed668fd64b0795c91035bef8cc6..8f175ece345b67bb4d276131aa97f1fce139d31c 100644 (file)
@@ -119,15 +119,11 @@ sendPADT(PPPoEConnection *conn, char const *msg)
     conn->session = 0;
 
     /* If we're using Host-Uniq, copy it over */
     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 */
     }
 
     /* Copy error message */
index 04877cb8295f767d90c989142da799a14c3fc4ec..16a59f77f09b0761951684d8868c277913066abd 100644 (file)
@@ -80,14 +80,10 @@ static void
 parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
                 void *extra)
 {
 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)
 {
 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 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 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 */
     }
 
     /* 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 */
     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 */
     }
 
     /* Add our maximum MTU/MRU */
index 48fcea832917561bccb9c7fa1deae2d14eb43fe4..9ceb66d8fcc034fceba9caa8e79f42284116370d 100644 (file)
@@ -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 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[] = {
 
 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" },
       "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,
+      "Set the Host-Uniq to the supplied hex string" },
     { NULL }
 };
 int (*OldDevnameHook)(char *cmd, char **argv, int doit) = NULL;
     { 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->ifName = devnam;
     conn->discoverySocket = -1;
     conn->sessionSocket = -1;
-    conn->useHostUniq = 1;
     conn->printACNames = printACNames;
     conn->discoveryTimeout = PADI_TIMEOUT;
     return 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 (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));
     conn->acName = acName;
     conn->serviceName = pppd_pppoe_service;
     strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
index 5afb037a1c74c74448851f6c75a1218810a912db..8b2e946f4d711d516e6f43fc73dbd45405c8b7a9 100644 (file)
@@ -357,7 +357,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 (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, &forMe);
     return forMe;
@@ -495,16 +495,12 @@ sendPADI(PPPoEConnection *conn)
     cursor += namelen + TAG_HDR_SIZE;
 
     /* If we're using Host-Uniq, copy it over */
     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);
     }
 
     packet.length = htons(plen);
@@ -670,7 +666,7 @@ int main(int argc, char *argv[])
     conn->discoveryTimeout = PADI_TIMEOUT;
     conn->discoveryAttempts = MAX_PADI_ATTEMPTS;
 
     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);
        switch(opt) {
        case 'S':
            conn->serviceName = xstrdup(optarg);
@@ -697,7 +693,25 @@ int main(int argc, char *argv[])
            }
            break;
        case 'U':
            }
            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");
            break;
        case 'D':
            conn->debugFile = fopen(optarg, "w");
@@ -778,6 +792,7 @@ void usage(void)
            "   -S name        -- Set desired service name.\n"
            "   -C name        -- Set desired access concentrator name.\n"
            "   -U             -- Use Host-Unique to allow multiple PPPoE sessions.\n"
            "   -S name        -- Set desired service name.\n"
            "   -C name        -- Set desired access concentrator name.\n"
            "   -U             -- Use Host-Unique to allow multiple PPPoE sessions.\n"
+           "   -W hexvalue    -- Set the Host-Unique to the supplied hex string.\n"
            "   -h             -- Print usage information.\n");
     fprintf(stderr, "\nVersion " RP_VERSION "\n");
 }
            "   -h             -- Print usage information.\n");
     fprintf(stderr, "\nVersion " RP_VERSION "\n");
 }
index 20318cb44a76ded0b9b394c245624cae5d460e76..b4b309fbeb04ed2c36cd08bf7aa8d0eeed95cb5c 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <stdio.h>             /* For FILE */
 #include <sys/types.h>         /* For pid_t */
 
 #include <stdio.h>             /* For FILE */
 #include <sys/types.h>         /* For pid_t */
+#include <ctype.h>
+#include <string.h>
 
 #include "pppd/pppd.h"         /* For error */
 
 
 #include "pppd/pppd.h"         /* For error */
 
@@ -234,7 +236,7 @@ typedef struct PPPoEConnectionStruct {
     char *serviceName;         /* Desired service name, if any */
     char *acName;              /* Desired AC name, if any */
     int synchronous;           /* Use synchronous PPP */
     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 */
     int printACNames;          /* Just print AC names */
     FILE *debugFile;           /* Debug file for dumping packets */
     int numPADOs;              /* Number of PADO packets received */
@@ -291,6 +293,32 @@ void pppoe_printpkt(PPPoEPacket *packet,
                    void (*printer)(void *, char *, ...), void *arg);
 void pppoe_log_packet(const char *prefix, 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 % 2 || len / 2 > sizeof(tag->payload))
+        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) \
 #define SET_STRING(var, val) do { if (var) free(var); var = strDup(val); } while(0);
 
 #define CHECK_ROOM(cursor, start, len) \