Skip to content

Commit

Permalink
raw option support
Browse files Browse the repository at this point in the history
Submitted by: @marjohn56
  • Loading branch information
fichtner committed Apr 3, 2018
1 parent fae5d4c commit a716d4b
Show file tree
Hide file tree
Showing 6 changed files with 316 additions and 3 deletions.
65 changes: 65 additions & 0 deletions cfparse.y
Expand Up @@ -41,6 +41,11 @@
#include <stdlib.h>
#include <string.h>

/* XXX */

#include <stdio.h>
#include <ctype.h>

#include "dhcp6.h"
#include "config.h"
#include "common.h"
Expand Down Expand Up @@ -157,6 +162,9 @@ void cf_init(void);
%type <range> rangeparam
%type <pool> poolparam

/* XXX */
%token RAW

%%
statements:
/* empty */
Expand Down Expand Up @@ -676,6 +684,63 @@ dhcpoption:
/* currently no value */
$$ = l;
}
/* XXX */
| RAW NUMBER STRING
{
struct cf_list *l;
struct rawoption *rawop;
char *tmp, *opstr = $2, *datastr = $3;

yywarn("Got raw option: %s %s", opstr, datastr);

if ((rawop = malloc(sizeof(*rawop))) == NULL) {
yywarn("can't allocate memory");
free(datastr);
free(opstr);
return (-1);
}

/* convert op num */
rawop->opnum = (int)strtol(opstr, NULL, 10);

/* convert string to lowercase */
tmp = datastr;
for ( ; *tmp; ++tmp) *tmp = tolower(*tmp);

/* allocate buffer */
int len = strlen(datastr);
len -= len / 3; /* remove ':' from length */
len = len / 2; /* byte length */
rawop->datalen = len;

if ((rawop->data = malloc(len)) == NULL) {
yywarn("can't allocate memory");
free(datastr);
free(opstr);
return (-1);
}

/* convert hex string to byte array */
char *h = datastr;
char *b = rawop->data;
char xlate[] = "0123456789abcdef";
int p1, p2, i = 0;

for ( ; *h; h += 3, ++b) { /* string is xx(:xx)\0 */
p1 = (int)(strchr(xlate, *h) - xlate);
p2 = (int)(strchr(xlate, *(h+1)) - xlate);
*b = (char)((p1 * 16) + p2);
}
//free(datastr);
//free(opstr);

yywarn("Raw option %d length %d stored at %p with data at %p",
rawop->opnum, rawop->datalen, (void*)rawop, (void*)rawop->data);

MAKE_CFLIST(l, DHCPOPT_RAW, NULL, NULL);
l->ptr = rawop;
$$ = l;
}
| DNS_SERVERS
{
struct cf_list *l;
Expand Down
14 changes: 14 additions & 0 deletions cftoken.l
Expand Up @@ -118,6 +118,9 @@ slash \/
bcl \{
ecl \}
/* XXX */
hexdata {hexpair}(:{hexpair})*
%s S_CNF
%s S_IFACE
%s S_PREF
Expand All @@ -129,6 +132,8 @@ ecl \}
%s S_SECRET
%s S_ADDRPOOL
%s S_INCL
/* XXX */
%s S_RAW
%%
%{
Expand Down Expand Up @@ -214,6 +219,15 @@ ecl \}
<S_CNF>bcmcs-server-address { DECHO; return (BCMCS_SERVERS); }
<S_CNF>bcmcs-server-domain-name { DECHO; return (BCMCS_NAME); }
<S_CNF>refreshtime { DECHO; return (REFRESHTIME); }
/* XXX */
<S_CNF>raw-option { DECHO; BEGIN S_RAW; return (RAW); }
<S_RAW>{integer} { DECHO; yylval.str = strdup(yytext); return(NUMBER); }
<S_RAW>{hexdata} {
DECHO;
yylval.str = strdup(yytext);
BEGIN S_CNF;
return (STRING);
}
/* provided for a backward compatibility to WIDE-DHCPv6 before Oct 1 2006 */
<S_CNF>nis-server-domain-name { DECHO; return (NIS_NAME); }
Expand Down
149 changes: 149 additions & 0 deletions common.c
Expand Up @@ -114,6 +114,104 @@ static ssize_t gethwid(char *, int, const char *, uint16_t *);
static char *sprint_uint64(char *, int, uint64_t);
static char *sprint_auth(struct dhcp6_optinfo *);

/* XXX */
int
rawop_count_list(head)
struct rawop_list *head;
{
struct rawoption *op;
int i;

//dprintf(LOG_INFO, FNAME, "counting list at %p", (void*)head);

for (i = 0, op = TAILQ_FIRST(head); op; op = TAILQ_NEXT(op, link)) {
i++;
}

return (i);
}

void
rawop_clear_list(head)
struct rawop_list *head;
{
struct rawoption *op;

//dprintf(LOG_INFO, FNAME, "clearing %d rawops at %p", rawop_count_list(head), (void*)head);

while ((op = TAILQ_FIRST(head)) != NULL) {

//dprintf(LOG_INFO, FNAME, " current op: %p link: %p", (void*)op, op->link);
TAILQ_REMOVE(head, op, link);

if (op->data != NULL) {
d_printf(LOG_INFO, FNAME, " freeing op data at %p", (void*)op->data);
free(op->data);
}
free(op); // Needed?
}
return;
}

int
rawop_copy_list(dst, src)
struct rawop_list *dst, *src;
{
struct rawoption *op, *newop;

/*
d_printf(LOG_INFO, FNAME,
" copying rawop list %p to %p (%d ops)",
(void*)src, (void*)dst, rawop_count_list(src));
*/

for (op = TAILQ_FIRST(src); op; op = TAILQ_NEXT(op, link)) {
newop = NULL;
if ((newop = malloc(sizeof(*newop))) == NULL) {
d_printf(LOG_ERR, FNAME,
"failed to allocate memory for a new raw option");
goto fail;
}
memset(newop, 0, sizeof(*newop));

newop->opnum = op->opnum;
newop->datalen = op->datalen;
newop->data = NULL;

/* copy data */
if ((newop->data = malloc(newop->datalen)) == NULL) {
d_printf(LOG_ERR, FNAME,
"failed to allocate memory for new raw option data");
goto fail;
}
memcpy(newop->data, op->data, newop->datalen);
//dprintf(LOG_INFO, FNAME, " copied %d bytes of data at %p", newop->datalen, (void*)newop->data);

TAILQ_INSERT_TAIL(dst, newop, link);
}
return (0);

fail:
rawop_clear_list(dst);
return (-1);
}

void
rawop_move_list(dst, src)
struct rawop_list *dst, *src;
{
struct rawoption *op;
/*
d_printf(LOG_INFO, FNAME,
" moving rawop list of %d from %p to %p",
rawop_count_list(src), (void*)src, (void*)dst);
*/
while ((op = TAILQ_FIRST(src)) != NULL) {
TAILQ_REMOVE(src, op, link);
TAILQ_INSERT_TAIL(dst, op, link);
}
}

int
dhcp6_copy_list(struct dhcp6_list *dst, struct dhcp6_list *src)
{
Expand Down Expand Up @@ -1319,6 +1417,9 @@ dhcp6_init_options(optinfo)
TAILQ_INIT(&optinfo->bcmcs_list);
TAILQ_INIT(&optinfo->bcmcsname_list);

/* XXX */
TAILQ_INIT(&optinfo->rawops);

optinfo->authproto = DHCP6_AUTHPROTO_UNDEF;
optinfo->authalgorithm = DHCP6_AUTHALG_UNDEF;
optinfo->authrdm = DHCP6_AUTHRDM_UNDEF;
Expand Down Expand Up @@ -1362,6 +1463,9 @@ dhcp6_clear_options(optinfo)
if (optinfo->ifidopt_id != NULL)
free(optinfo->ifidopt_id);

/* XXX */
rawop_clear_list(&optinfo->rawops);

dhcp6_init_options(optinfo);
}

Expand Down Expand Up @@ -1411,6 +1515,9 @@ dhcp6_copy_options(dst, src)
dst->refreshtime = src->refreshtime;
dst->pref = src->pref;

/* XXX */
rawop_copy_list(&dst->rawops, &src->rawops);

if (src->relaymsg_msg != NULL) {
if ((dst->relaymsg_msg = malloc(src->relaymsg_len)) == NULL)
goto fail;
Expand Down Expand Up @@ -1479,6 +1586,9 @@ dhcp6_get_options(p, ep, optinfo)
struct dhcp6_list sublist;
int authinfolen;

/* XXX */
struct rawoption *rawop;

bp = (char *)p;
for (; p + 1 <= ep; p = np) {
struct duid duid0;
Expand Down Expand Up @@ -1679,6 +1789,15 @@ dhcp6_get_options(p, ep, optinfo)
case DHCP6_AUTHPROTO_RECONFIG:
break;
#endif
/* XXX */
case 0:
// Discard auth
d_printf(LOG_DEBUG, FNAME, " Discarding null authentication");
optinfo->authproto = DHCP6_AUTHPROTO_UNDEF;
optinfo->authalgorithm = DHCP6_AUTHALG_UNDEF;
optinfo->authrdm = DHCP6_AUTHRDM_UNDEF;
break;

default:
d_printf(LOG_INFO, FNAME,
"unsupported authentication protocol: %d",
Expand Down Expand Up @@ -1854,6 +1973,16 @@ dhcp6_get_options(p, ep, optinfo)
dhcp6_clear_list(&sublist);

break;

/* XXX */
case DHCPOPT_RAW:
rawop = (struct rawoption *) cp;
d_printf(LOG_DEBUG, FNAME,
"raw option: %d",
rawop->opnum);
TAILQ_INSERT_TAIL(&optinfo->rawops, rawop, link);
break;

default:
/* no option specific behavior */
d_printf(LOG_INFO, FNAME,
Expand Down Expand Up @@ -2230,6 +2359,8 @@ dhcp6_set_options(type, optbp, optep, optinfo)
struct dhcp6_listval *stcode, *op;
int len = 0, optlen;
char *tmpbuf = NULL;
/* XXX */
struct rawoption *rawop;

if (optinfo->clientID.duid_len) {
if (copy_option(DH6OPT_CLIENTID, optinfo->clientID.duid_len,
Expand Down Expand Up @@ -2446,6 +2577,20 @@ dhcp6_set_options(type, optbp, optep, optinfo)
goto fail;
}
}
/* XXX */
for (rawop = TAILQ_FIRST(&optinfo->rawops); rawop;
rawop = TAILQ_NEXT(rawop, link)) {

d_printf(LOG_DEBUG, FNAME,
" raw option %d length %d at %p",
rawop->opnum, rawop->datalen, (void*)rawop);

if (copy_option(rawop->opnum, rawop->datalen,
rawop->data, &p,
optep, &len) != 0) {
goto fail;
}
}

if (optinfo->authproto != DHCP6_AUTHPROTO_UNDEF) {
struct dhcp6opt_auth *auth;
Expand Down Expand Up @@ -3027,6 +3172,10 @@ dhcp6optstr(type)
return ("subscriber ID");
case DH6OPT_CLIENT_FQDN:
return ("client FQDN");
/* XXX */
case DHCPOPT_RAW:
return ("raw");

default:
snprintf(genstr, sizeof(genstr), "opt_%d", type);
return (genstr);
Expand Down

1 comment on commit a716d4b

@marjohn56
Copy link
Member

@marjohn56 marjohn56 commented on a716d4b Apr 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the notes from my original commit on HRS - I'll try and flesh them out a bit when I get some time,

The changes here add the ability to add as many options as needed using the RAW parameter.

For example, these are taken from a working system, slightly changed to protect the user!

User class "+FSVDSL_livebox.Internet.softathome.Livebox3";

send raw-option 15 00:2b:46:53:56:44:53:4c:5f:6c:69:76:65:62:6f:78:2e:49:6e:74:65:72:6e:65:74:2e:73:6f:66:74:61:74:68:6f:6d:65:2e:6c:69:76:65:62:6f:78:33;

Vendor class "sagem"

send raw-option 16 00:00:04:0e:00:05:73:61:67:65:6d;

Authentication

send raw-option 11 00:00:00:00:00:00:00:00:00:00:00:61:71:81:2d:66:73:71:71:36:41:78;

It can be seen that the option number is the first number after the "send raw-option, entered as a decimal number.

For example, in the User Class, rfc3315 states that for user class, all that is required is the option length - first byte, then the string itself. As the length will be calculated and entered automatically this is set to 0, or in hex 00. The string is then entered, converted to hex bytes as shown below.

+FSVDSL_livebox.Internet.softathome.Livebox3

becomes

00:2b:46:53:56:44:53:4c:5f:6c:69:76:65:62:6f:78:2e:49:6e:74:65:72:6e:65:74:2e:73:6f:66:74:61:74:68:6f:6d:65:2e:6c:69:76:65:62:6f:78:33

Care obviously needs to be taken when creating these parameters and it is for the advanced only, but it does allow any option(s) to be added, and it works!

It is imperative that when adding a RAW option that the RFC for that option is studied, Each RAW option is different. Some are fixed length, some are not. All must be entered in HEX format. At the end of the day, it may be required to use wireshark or a packet capture to ensure the correct string is being sent.

Please sign in to comment.