Skip to content

Commit

Permalink
Merge pull request #1070 from pi-hole/fix/escape-user-strings
Browse files Browse the repository at this point in the history
Escape DHCP options if necessary
  • Loading branch information
DL6ER authored Mar 2, 2021
2 parents 3fd9b8d + 0a6ffb7 commit 6d5c118
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 20 deletions.
66 changes: 46 additions & 20 deletions src/dhcp-discover.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,14 +277,12 @@ static void print_dhcp_offer(struct in_addr source, dhcp_packet_data *offer_pack
}
else if(opttab[i].size & OT_NAME)
{
char name[optlen+1];
memcpy(&name, &offer_packet->options[x], optlen);
name[optlen] = '\0';

if(iscntrl(name[0]))
logg("%s: <cntrl sequence> (length %u)", opttab[i].name, optlen);
else
logg("%s: \"%s\"", opttab[i].name, name);
// We may need to escape this, buffer size: 4
// chars per control character plus room for
// possible "(empty)"
char buffer[4*optlen + 9];
binbuf_to_escaped_C_literal(&offer_packet->options[x], optlen, buffer, sizeof(buffer));
logg("%s: \"%s\"", opttab[i].name, buffer);
}
else if(opttab[i].size & OT_TIME)
{
Expand Down Expand Up @@ -363,19 +361,37 @@ static void print_dhcp_offer(struct in_addr source, dhcp_packet_data *offer_pack
if(!found)
{
if(opttype == 252) // WPAD configuration (this is a non-standard extension)
{ // see INTERNET-DRAFT Web Proxy Auto-Discovery Protocol
// https://tools.ietf.org/html/draft-ietf-wrec-wpad-01
char wpad_server[optlen+1];
memcpy(&wpad_server, &offer_packet->options[x], optlen);
wpad_server[optlen] = '\0';
if(iscntrl(wpad_server[0]))
logg("wpad-server: <cntrl sequence> (length %u)", optlen);
else
logg("wpad-server: \"%s\"", wpad_server);
{ // see INTERNET-DRAFT Web Proxy Auto-Discovery Protocol
// https://tools.ietf.org/html/draft-ietf-wrec-wpad-01
// We may need to escape this, buffer size: 4
// chars per control character plus room for
// possible "(empty)"
char buffer[4*optlen + 9];
binbuf_to_escaped_C_literal(&offer_packet->options[x], optlen, buffer, sizeof(buffer));
logg("wpad-server: \"%s\"", buffer);
}
else if(opttype == 158) // DHCPv4 PCP Option (RFC 7291)
{ // https://tools.ietf.org/html/rfc7291#section-4
uint16_t list_length = offer_packet->options[x++] / 4; // 4 bytes per list entry
// Loop over IPv4 lists
for(unsigned int n = 0; n < list_length; n++)
{
struct in_addr addr_list = { 0 };
memcpy(&addr_list.s_addr, &offer_packet->options[x+n*4], sizeof(addr_list.s_addr));
if(n > 0)
logg_sameline(" ");

logg("Port Control Protocol (PCP) server: %s", inet_ntoa(addr_list));
}
}
else
{
logg("Unknown option %d with length %d", opttype, optlen);
logg_sameline("Unknown option %d:", opttype);
// Print bytes
for(unsigned i = 0; i < optlen; i++)
logg_sameline(" %02X", (unsigned char)offer_packet->options[x+i]);
// Add newline when done above
logg(" (length %d)", optlen);
}
}

Expand Down Expand Up @@ -502,13 +518,23 @@ static bool get_dhcp_offer(const int sock, const uint32_t xid, const char *iface

logg_sameline(" BOOTP server: ");
if(offer_packet.sname[0] != 0)
logg("%s", offer_packet.sname);
{
size_t len = strlen(offer_packet.sname);
char buffer[4*len + 9];
binbuf_to_escaped_C_literal(offer_packet.sname, len, buffer, sizeof(buffer));
logg("%s", buffer);
}
else
logg("(empty)");

logg_sameline(" BOOTP file: ");
if(offer_packet.file[0] != 0)
logg("%s", offer_packet.file);
{
size_t len = strlen(offer_packet.file);
char buffer[4*len + 9];
binbuf_to_escaped_C_literal(offer_packet.file, len, buffer, sizeof(buffer));
logg("%s", buffer);
}
else
logg("(empty)");

Expand Down
76 changes: 76 additions & 0 deletions src/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,79 @@ const char __attribute__ ((const)) *get_ordinal_suffix(unsigned int number)
}
// For example: 2nd, 7th, 20th, 23rd, 52nd, 135th, 301st BUT 311th (covered above)
}

// Converts a buffer of specified lenth to ASCII representation as it was a C
// string literal. Returns how much bytes from source was processed
// Inspired by https://stackoverflow.com/a/56123950
int binbuf_to_escaped_C_literal(const char *src_buf, size_t src_sz,
char *dst_str, size_t dst_sz)
{
const char *src = src_buf;
char *dst = dst_str;

// Special handling for empty strings
if(src_sz == 0)
{
strncpy(dst_str, "(empty)", dst_sz);
dst_str[dst_sz-1] = '\0';
return 0;
}

while (src < src_buf + src_sz)
{
if (isprint(*src))
{
// The printable characters are:
// ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ;
// < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V
// W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q
// r s t u v w x y z { | } ~
*dst++ = *src++;
}
else if (*src == '\\')
{
// Backslash isn't included above but isn't harmful
*dst++ = '\\';
*dst++ = *src++;
}
else
{
// Handle other characters more specifically
switch(*src)
{
case '\n':
*dst++ = '\\';
*dst++ = 'n';
break;
case '\r':
*dst++ = '\\';
*dst++ = 'r';
break;
case '\t':
*dst++ = '\\';
*dst++ = 't';
break;
case '\0':
*dst++ = '\\';
*dst++ = '0';
break;
default:
sprintf(dst, "0x%X", *src);
dst += 4;
}

// Advance reading counter by one character
src++;
}

// next iteration requires up to 5 chars in dst buffer, for ex.
// "0x04" + terminating zero (see below)
if (dst > (dst_str + dst_sz - 5))
break;
}

// Zero-terminate buffer
*dst = '\0';

return src - src_buf;
}
2 changes: 2 additions & 0 deletions src/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ void FTL_log_dnsmasq_fatal(const char *format, ...) __attribute__ ((format (gnu_
void log_ctrl(bool vlog, bool vstdout);
void FTL_log_helper(const unsigned char n, ...);

int binbuf_to_escaped_C_literal(const char *src_buf, size_t src_sz, char *dst_str, size_t dst_sz);

#endif //LOG_H

0 comments on commit 6d5c118

Please sign in to comment.