diff --git a/CHANGELOG.md b/CHANGELOG.md
index d1d530d..fc1755b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+## 0.4.3 - 2019-03-19
+### Added
+- DHCP option names are printed along with their option codes.
+
+### Changed
+- Debug output is more detailed and aligned.
+
+### Fixed
+- Alignment and explicit data type conversions are used to compile without
+ errors on 32-bit architectures.
+- Do not fail on strict-overflow warnings, as some may be ignored.
+- Do not use non-ASCII characters in debug output. They were not strictly
+ needed.
+
## 0.4.2 - 2019-01-17
### Changed
- Change usage string to reflect formatting used by man page.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9fb3cd2..81f3e4a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,7 +31,36 @@ set(HEADERS
)
add_executable(dhcpoptinj ${SOURCES} ${HEADERS})
set_property(TARGET dhcpoptinj PROPERTY C_STANDARD 99)
-target_compile_options(dhcpoptinj PRIVATE -Wall -Wextra -pedantic -Wcast-align -Wcast-qual -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wredundant-decls -Wshadow -Wsign-conversion -Wstrict-overflow=5 -Wswitch-default -Wundef -Werror -Wno-unused -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -fstack-protector -Wwrite-strings -D_POSIX_SOURCE -D_DEFAULT_SOURCE -D_FORTIFY_SOURCE=2)
+target_compile_options(dhcpoptinj PRIVATE
+ -Wall
+ -Wextra
+ -pedantic
+ -Wcast-align
+ -Wcast-qual
+ -Wdisabled-optimization
+ -Wformat=2
+ -Winit-self
+ -Wlogical-op
+ -Wmissing-declarations
+ -Wmissing-include-dirs
+ -Wredundant-decls
+ -Wshadow
+ -Wsign-conversion
+ -Wstrict-overflow=5
+ -Wno-error=strict-overflow
+ -Wswitch-default
+ -Wundef
+ -Werror
+ -Wno-unused
+ -Wmissing-prototypes
+ -Wstrict-prototypes
+ -Wold-style-definition
+ -fstack-protector
+ -Wwrite-strings
+ -D_POSIX_SOURCE
+ -D_DEFAULT_SOURCE
+ -D_FORTIFY_SOURCE=2
+ )
find_library(NFQ_LIB netfilter_queue REQUIRED)
target_link_libraries(dhcpoptinj ${NFQ_LIB})
diff --git a/docs/dhcpoptinj.8 b/docs/dhcpoptinj.8
deleted file mode 100644
index a07de3b..0000000
--- a/docs/dhcpoptinj.8
+++ /dev/null
@@ -1,222 +0,0 @@
-'\" t
-.\"
-.\" Copyright © 2019 Andreas Misje
-.\"
-.\" This file is part of dhcpoptinj.
-.\"
-.\" dhcpoptinj is free software: you can redistribute it and/or modify it under
-.\" the terms of the GNU General Public License as published by the Free
-.\" Software Foundation, either version 3 of the License, or (at your option)
-.\" any later version.
-.\"
-.\" dhcpoptinj is distributed in the hope that it will be useful, but WITHOUT
-.\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-.\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-.\" more details.
-.\"
-.\" You should have received a copy of the GNU General Public License along
-.\" with dhcpoptinj. If not, see .
-.\"
-.
-.Dd February 10, 2019
-.Dt DHCPOPTINJ 8
-.Os
-.Sh NAME
-.Nm dhcpoptinj
-.Nd DHCP option injector, a tool to manipulate DHCP packet options
-.Sh SYNOPSIS
-.Nm
-.Bk
-.Op Fl df
-.Ek
-.Bk
-.Op Fl Fl forward-on-fail
-.Ek
-.Bk
-.Op Fl i Ns | Ns Fl r
-.Ek
-.Bk
-.Op Fl p Op Ar pid_file
-.Ek
-.Bk
-.Fl q Ar queue_num
-.Ek
-.Bk
-.Fl o Ar dhcp_option
-.Ek
-.Bk
-.Op Po Fl o Ar dhcp_option Pc ...
-.Ek
-.Bk
-.Nm
-.Fl h Ns | Ns Fl v
-.Ek
-.Sh DESCRIPTION
-.Nm
-is a fairly simple tool for manipulating DHCP options in a BOOTP/DHCP packet.
-It relies on netfilter queue and nftables/iptables rules, in which you specify what packets to send to
-.Nm .
-.Nm
-waits for packets to arrive in a netfilter queue.
-It will ensure that a packet is in fact a BOOTP/DHCP packet, and if so proceed to inject or replace options.
-It will recalculate the IPv4 header checksum, disable the UDP checksum (for a simpler implementation) and then give the packet back to netfilter.
-.Pp
-Based on the options
-.Fl Fl ignore-existing-opt
-and
-.Fl Fl remove-existing-opt
-.Nm
-may be configured to replace matching options or leave them in place.
-.Fl Fl forward-on-fail
-can be used to accept the packet (leaving it unaltered) if the package mangling should fail for any reason.
-.Ss Invocation
-.Nm
-incorrectly requires flags to run.
-The netfilter queue number
-.Pq Fl Fl queue
-is necessary, and also at least one DHCP option
-.Pq Fl Fl option .
-See
-.Sx EXAMPLES .
-.Ss Argument list processing
-.Nm
-is invoked only with options and no arguments:
-.Bl -tag -width ".Fl r, .Fl .Fl remove-existing-opt" -offset indent
-.It Fl d , Fl Fl debug
-Make
-.Nm
-tell you as much as possible about what it does and tries to do.
-.It Fl f , Fl Fl foreground
-Prevent
-.Nm
-from running in the background.
-.It "\ \ \ " Fl Fl forward-on-fail
-If the process of injecting options should fail, let the unaltered DHCP packet pass through.
-The default behaviour is to drop the packet if options could not be injected.
-.It Fl h , Fl Fl help
-Print a help text.
-.It Fl i , Fl Fl ignore-existing-opt
-Proceed if an injected option already exists in the original packet.
-Unless
-.Fl Fl remove-existing-opt
-is provided, the default behaviour is to drop the packet.
-.It Fl o , Fl Fl option Ar dhcp_option
-DHCP option to inject as a hex string, where the first byte indicates the option code.
-The option length field is automatically calculated and must be omitted.
-Several options may be injected.
-.Pp
-The hex string may be delimited by non-hexadecimal characters for readability.
-The following hex strings all produce the same result: '01 02 03', '01:02:03', '010203', '01 <-> 02 <-> 03'.
-Remember to quote these arguments if they contains spaces or other characters that have special meaning to your shell.
-.It Fl p , Fl Fl pid-file Op Pa pid_file
-Write PID to file, using specified path or a default sensible location.
-.It Fl q , Fl Fl queue Ar queue_num
-The netfilter queue number to use
-.It Fl r , Fl Fl remove-existing-opt
-Remove existing DHCP options of the same kind as those to be injected.
-.It Fl v , Fl Fl version
-Display version.
-.El
-.Pp
-.Ss DHCP options
-All the DHCP options specified with the
-.Fl o Ns / Ns Fl Fl option
-flag will be added before the terminating option (end option, 255).
-The packet is padded if necessary and sent back to netfilter.
-The IPv4 header checksum is recalculated, but the UDP checksum is set to 0 (disabled).
-None of the added options are checked for whether they are valid, or whether the option codes are valid.
-Options are currently not (automatically) padded individually, but they can be manually padded by adding options with code 0 (one pad byte per option).
-This special option is the only option that does not have any payload (the end option, 255, is inserted automatically and cannot be manually added).
-Padding individual options should not be necessary.
-.Pp
-The option hex string is written as a series of two-digit pairs,
-optionally delimited by one or more non-hexadecimal characters: '466A6173','46 6A 61 73', '46:6A:61:73' etc.
-There is a maximum limit of 256 bytes per option, excluding the option code (the first byte) and the automatically inserted length byte.
-At least one option must be provided.
-.Pp
-If the packet already contains a DHCP option that is to be injected (matched by code), the behaviour depends on the command line options
-.Fl Fl ignore-existing-opt
-and
-.Fl Fl remove-existing-opt :
-.Bl -tag -width ".Pq none" -offset indent
-.It Pq none
-The packet will be dropped.
-.It Fl i
-The existing options are ignored and the injected options are added.
-.It Fl r
-Any existing options are removed and the injected options are added.
-.El
-.Pp
-.Em Note
-that injected options will not be injected in the same place as those that may have been removed if using
-.Fl r .
-However, this should not matter.
-.Sh EXIT STATUS
-.Ex -std dhcpoptinj
-.Sh EXAMPLES
-Let us say you have two interfaces bridged together, eth0 and eth1.
-Let us say you want to intercept all BOOTP requests coming from eth0 and inject the relay agent information option (82/0x52).
-Let us make up a silly payload: An agent circuit ID sub-option with the value "Fjas".
-.Pp
-Add a rule to the iptables mangle table:
-.Pp
-.Dl sudo iptables -t mangle -A PREROUTING -m physdev --physdev-in eth0 -p udp --dport 67 -j NFQUEUE --queue-num 42
-.Pp
-Then run
-.Nm
-(let us run it in the foreground with extra debug output):
-.Pp
-.Dl sudo dhcpoptinj -d -f -q 42 -o'52 01 04 46 6A 61 73'
-.Pp
-.Em Note
-that
-.Nm
-must be run by a user with the CAP_NET_ADMIN capability.
-You do not need to, and you really should not run
-.Nm
-as root.
-Instead, you can for instance grant the CAP_NET_ADMIN capability to the binary (using
-.Em setcap )
-and limit execution rights to only a specific user or group.
-This is a method used for running Wireshark as non-root, so you will find several guides helping you accomplish this.
-.Pp
-Now send a DHCP packet to the eth0 interface and watch it (using a tool like Wireshark
-.Pq Lk https://\:www.wireshark.org/
-having been modified when it reaches the bridged interface.
-It should have the injected option at the end of the option list.
-If you capture the incoming DHCP packet with Wireshark, it will appear unmodified although it will in fact be mangled.
-.Pp
-Note the format of the argument to the
-.Fl o
-option: It should be a hexadecimal string starting with the DHCP option code followed by the option payload.
-The option length (the byte that normally follows the option code) is automatically calculated and must not be specified.
-The hex string can be delimited by non-hexadecimal characters for readability.
-All options must have a payload, except for the special pad option
-.Pq Lk https://\:tools.ietf.org/\:html/\:rfc2132#section-2
-(code 0).
-.Pp
-The layout of the nonsensical option used in this example, 52 01 04 46 6A 61 73, (first the DHCP option layout
-.Pq Lk https://\:tools.ietf.org/\:html/\:rfc2132#section-2 ,
-then the specific relay agent information option sub-option layout
-.Pq Lk https://tools.ietf.org/html/rfc3046#section-2.0 )
-is as follows:
-.Pp
-.TS
-allbox tab(;);
-c c c
-c c c.
-Code;Length;Data
-52;(auto);01 04 46 6A 61 73 ("Fjas")
-.TE
-.Pp
-.TS
-allbox tab(;);
-c c c
-c c c.
-Sub-opt.;Lenth;Data
-01;4;46 6A 61 73 ("Fjas")
-.TE
-.Sh SEE ALSO
-iptables(8), nftables(8), dhcp-options(5)
-.Sh AUTHORS
-.An "Andreas Misje" Aq amisje@gmail.com
diff --git a/src/config.c b/src/config.c
index c4c1419..23af516 100644
--- a/src/config.c
+++ b/src/config.c
@@ -252,11 +252,11 @@ static struct Config *createDefaultConfig(void)
static void printUsage(const char *programName)
{
- int progNameLen = strlen(programName);
+ int progNameLen = (int)strlen(programName);
printf(
"%s – DHCP option injector\n"
"Usage: %s [-df] [--forward-on-fail] [-i|-r] [-p [pid_file]] \n"
- " %*s -q queue_num -o dhcp_option [(-o dhcp_option) …]\n"
+ " %*s -q queue_num -o dhcp_option [(-o dhcp_option) ...]\n"
" %s -h|-v\n"
,
programName,
diff --git a/src/dhcp.c b/src/dhcp.c
index 4d4b04a..0635e8c 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -43,3 +43,184 @@ const char *dhcp_msgTypeString(uint8_t msgType)
return "??";
}
}
+
+const char *dhcp_optionString(uint8_t option)
+{
+ // From https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml
+ static const char * const names[] =
+ {
+ [0] = "Pad",
+ [1] = "Subnet Mask",
+ [2] = "Time Offset",
+ [3] = "Router",
+ [4] = "Time Server",
+ [5] = "Name Server",
+ [6] = "Domain Server",
+ [7] = "Log Server",
+ [8] = "Quotes Server",
+ [9] = "LPR Server",
+ [10] = "Impress Server",
+ [11] = "RLP Server",
+ [12] = "Hostname",
+ [13] = "Boot File Size",
+ [14] = "Merit Dump File",
+ [15] = "Domain Name",
+ [16] = "Swap Server",
+ [17] = "Root Path",
+ [18] = "Extension File",
+ [19] = "Forward On/Off",
+ [20] = "SrcRte On/Off",
+ [21] = "Policy Filter",
+ [22] = "Max DG Assembly",
+ [23] = "Default IP TTL",
+ [24] = "MTU Timeout",
+ [25] = "MTU Plateau",
+ [26] = "MTU Interface",
+ [27] = "MTU Subnet",
+ [28] = "Broadcast Address",
+ [29] = "Mask Discovery",
+ [30] = "Mask Supplier",
+ [31] = "Router Discovery",
+ [32] = "Router Request",
+ [33] = "Static Route",
+ [34] = "Trailers",
+ [35] = "ARP Timeout",
+ [36] = "Ethernet",
+ [37] = "Default TCP TTL",
+ [38] = "Keepalive Time",
+ [39] = "Keepalive Data",
+ [40] = "NIS Domain",
+ [41] = "NIS Servers",
+ [42] = "NTP Servers",
+ [43] = "Vendor Specific",
+ [44] = "NETBIOS Name Srv",
+ [45] = "NETBIOS Dist Srv",
+ [46] = "NETBIOS Node Type",
+ [47] = "NETBIOS Scope",
+ [48] = "X Window Font",
+ [49] = "X Window Manager",
+ [50] = "Address Request",
+ [51] = "Address Time",
+ [52] = "Overload",
+ [53] = "DHCP Msg Type",
+ [54] = "DHCP Server Id",
+ [55] = "Parameter List",
+ [56] = "DHCP Message",
+ [57] = "DHCP Max Msg Size",
+ [58] = "Renewal Time",
+ [59] = "Rebinding Time",
+ [60] = "Class Id",
+ [61] = "Client Id",
+ [62] = "NetWare/IP Domain",
+ [63] = "NetWare/IP Option",
+ [64] = "NIS-Domain-Name",
+ [65] = "NIS-Server-Addr",
+ [66] = "Server-Name",
+ [67] = "Bootfile-Name",
+ [68] = "Home-Agent-Addrs",
+ [69] = "SMTP-Server",
+ [70] = "POP3-Server",
+ [71] = "NNTP-Server",
+ [72] = "WWW-Server",
+ [73] = "Finger-Server",
+ [74] = "IRC-Server",
+ [75] = "StreetTalk-Server",
+ [76] = "STDA-Server",
+ [77] = "User-Class",
+ [78] = "Directory Agent",
+ [79] = "Service Scope",
+ [80] = "Rapid Commit",
+ [81] = "Client FQDN",
+ [82] = "Relay Agent Information",
+ [83] = "iSNS",
+ // 84 removed/unassigned
+ [85] = "NDS Servers",
+ [86] = "NDS Tree Name",
+ [87] = "NDS Context",
+ [88] = "BCMCS Controller Domain Name list",
+ [89] = "BCMCS Controller IPv4 address option",
+ [90] = "Authentication",
+ [91] = "client-last-transaction-time option",
+ [92] = "associated-ip option",
+ [93] = "Client System",
+ [94] = "Client NDI",
+ [95] = "LDAP",
+ // 96 removed/unassigned
+ [97] = "UUID/GUID",
+ [98] = "User-Auth",
+ [99] = "GEOCONF_CIVIC",
+ [100] = "PCode",
+ [101] = "TCode",
+ // 102–108 removed/unassigned
+ [109] = "OPTION_DHCP4O6_S46_SADDR",
+ // 110 removed/unassigned
+ // 111 removed/unassigned
+ [112] = "Netinfo Address",
+ [113] = "Netinfo Tag",
+ [114] = "URL",
+ // 115 removed/unassigned
+ [116] = "Auto-Config",
+ [117] = "Name Service Search",
+ [118] = "Subnet Selection Option",
+ [119] = "Domain Search",
+ [120] = "SIP Servers DHCP Option",
+ [121] = "Classless Static Route Option",
+ [122] = "CCC",
+ [123] = "GeoConf Option",
+ [124] = "V-I Vendor Class",
+ [125] = "V-I Vendor-Specific Information",
+ // 126 removed/unassigned
+ // 127 removed/unassigned
+ [128] = "PXE / Etherboot signature",
+ [129] = "PXE / Kernel options / Call Server IP address",
+ [130] = "PXE / Ethernet interface / Discrimination string",
+ [131] = "PXE / Remote statistics server IP address",
+ [132] = "PXE",
+ [133] = "PXE",
+ [134] = "PXE",
+ [135] = "PXE / HTTP Proxy for phone-specific applications",
+ [136] = "OPTION_PANA_AGENT",
+ [137] = "OPTION_V4_LOST",
+ [138] = "OPTION_CAPWAP_AC_V4",
+ [139] = "OPTION-IPv4_Address-MoS",
+ [140] = "OPTION-IPv4_FQDN-MoS",
+ [141] = "SIP UA Configuration Service Domains",
+ [142] = "OPTION-IPv4_Address-ANDSF",
+ [143] = "OPTION_V4_SZTP_REDIRECT",
+ [144] = "GeoLoc",
+ [145] = "FORCERENEW_NONCE_CAPABLE",
+ [146] = "RDNSS Selection",
+ // 147–149 unassigned
+ [150] = "TFTP server address / Etherboot / GRUB configuration path name",
+ [151] = "status-code",
+ [152] = "base-time",
+ [153] = "start-time-of-state",
+ [154] = "query-start-time",
+ [155] = "query-end-time",
+ [156] = "dhcp-state",
+ [157] = "data-source",
+ [158] = "OPTION_V4_PCP_SERVER",
+ [159] = "OPTION_V4_PORTPARAMS",
+ [160] = "DHCP Captive-Portal",
+ [161] = "OPTION_MUD_URL_V4",
+ // 162–174 unassigned
+ [175] = "Etherboot",
+ [176] = "IP Telephone",
+ [177] = "Etherboot / PacketCable and CableHome",
+ // 178–207 unassigned
+ [208] = "PXELINUX Magic",
+ [209] = "Configuration File",
+ [210] = "Path Prefix",
+ [211] = "Reboot Time",
+ [212] = "OPTION_6RD",
+ [213] = "OPTION_V4_ACCESS_DOMAIN",
+ // 214–219 unassigned
+ [220] = "Subnet Allocation Option",
+ [221] = "Virtual Subnet Selection (VSS) Option",
+ // 222–223 unassigned
+ // 224–254 reserved
+ [255] = "End",
+ };
+
+ return names[option] ? names[option] : "(unassigned/reserved)";
+}
diff --git a/src/dhcp.h b/src/dhcp.h
index 12772fc..7e5923b 100644
--- a/src/dhcp.h
+++ b/src/dhcp.h
@@ -27,6 +27,7 @@
#define DHCPOPT_END 0xff
#define DHCPOPT_TYPE 0x35
+#pragma pack(4)
struct BootP
{
uint8_t op;
@@ -45,15 +46,17 @@ struct BootP
uint8_t file[128];
uint32_t cookie;
// options …
-} __attribute__((packed));
+};
struct DHCPOption
{
uint8_t code;
uint8_t length;
uint8_t data[];
-} __attribute__((packed));
+};
+#pragma pack()
const char *dhcp_msgTypeString(uint8_t msgType);
+const char *dhcp_optionString(uint8_t option);
#endif // DHCPOPTINJ_DHCP_H
diff --git a/src/dhcpoptinj.c b/src/dhcpoptinj.c
index fcb4703..48cd5c3 100644
--- a/src/dhcpoptinj.c
+++ b/src/dhcpoptinj.c
@@ -38,6 +38,7 @@
#include "ipv4.h"
#include "udp.h"
#include "dhcp.h"
+#include
#define MIN_BOOTP_SIZE 300
@@ -56,10 +57,10 @@ enum MangleResult
};
/* Somewhat arbitrary, feel free to change */
-static const int maxPacketSize = 2048;
+static const uint32_t maxPacketSize = 2048;
/* The netfilter queue length 20 is also arbitrary. Hopefully it is
* sufficient. */
-static const int maxQueueLen = 20;
+static const uint32_t maxQueueLen = 20;
static struct Config *config;
static bool daemonised;
static sig_atomic_t escapeMainLoop;
@@ -92,7 +93,9 @@ static void inspectOptions(void);
/* Debug-print packet header */
static void debugLogPacketHeader(const uint8_t *data, size_t size);
/* Debug-print packet's existing DHCP options */
-static void debugLogOption(const struct DHCPOption *option);
+static void debugLogOptionFound(const struct DHCPOption *option);
+static void debugLogOption(const char *action, const struct DHCPOption *option);
+static void debugLogInjectedOptions(void);
int main(int argc, char *argv[])
{
@@ -103,7 +106,7 @@ int main(int argc, char *argv[])
debugLogOptions();
inspectOptions();
- logMessage(LOG_DEBUG, "Initialising netfilter queue …\n");
+ logMessage(LOG_DEBUG, "Initialising netfilter queue\n");
struct nfq_handle *nfq = nfq_open();
if (!nfq)
@@ -148,7 +151,7 @@ int main(int argc, char *argv[])
if (!config->foreground)
{
- logMessage(LOG_DEBUG, "Daemonising …\n");
+ logMessage(LOG_DEBUG, "Daemonising\n");
if (daemon(false, false))
{
logMessage(LOG_ERR, "Failed to daemonise: daemon() failed: %s\n",
@@ -163,7 +166,8 @@ int main(int argc, char *argv[])
initSignalHandler();
if (config->debug)
- logMessage(LOG_DEBUG, "Initialisation completed. Waiting for packets to mangle …\n");
+ logMessage(LOG_DEBUG, "Initialisation completed. Waiting for packets to "
+ "mangle on queue %" PRIu16 "\n", config->queue);
else
logMessage(LOG_INFO, "Started\n");
@@ -197,14 +201,14 @@ int main(int argc, char *argv[])
logMessage(LOG_NOTICE, "Caught signal %s\n", signalName);
}
- logMessage(LOG_DEBUG, "Destroying netfilter queue …\n");
+ logMessage(LOG_DEBUG, "Destroying netfilter queue\n");
nfq_destroy_queue(queue);
/* According to libnetfilter_queue's nfqnl_test.c example, nfq_unbind_pf(…)
* should NOT be called during clean up. */
nfq_close(nfq);
- logMessage(LOG_NOTICE, "Exiting …\n");
+ logMessage(LOG_NOTICE, "Exiting\n");
removePIDFile();
destroyConfig();
@@ -277,7 +281,7 @@ static int inspectPacket(struct nfq_q_handle *queue, struct nfgenmsg *pktInfo,
}
if (config->debug)
- logMessage(LOG_DEBUG, "Sending mangled packet …\n");
+ logMessage(LOG_DEBUG, "Sending mangled packet\n");
int res = nfq_set_verdict(queue, ntohl(metaHeader->packet_id), NF_ACCEPT,
mangledDataSize, mangledData);
@@ -369,7 +373,7 @@ static enum MangleResult manglePacket(const uint8_t *origData, size_t origDataSi
if (padding && config->debug)
logMessage(LOG_DEBUG, "Padding with %zu byte(s) to meet minimal BOOTP payload "
- "size …\n", padding);
+ "size\n", padding);
/* Pad to (at least) MIN_BOOTP_SIZE bytes: */
for (size_t i = *newDataSize - padding; i < *newDataSize; ++i)
@@ -401,7 +405,7 @@ static enum MangleResult mangleOptions(const uint8_t *origData, size_t origDataS
if (padCount)
logMessage(LOG_DEBUG, "Found %zu PAD options (removing)\n", padCount);
- debugLogOption(option);
+ debugLogOptionFound(option);
padCount = 0;
}
}
@@ -457,7 +461,7 @@ static enum MangleResult mangleOptions(const uint8_t *origData, size_t origDataS
}
if (config->debug)
- logMessage(LOG_DEBUG, "Injecting %zu option(s) …\n", config->dhcpOptCodeCount);
+ debugLogInjectedOptions();
/* Inject DHCP options: */
for (size_t i = 0; i < config->dhcpOptsSize; ++i)
@@ -466,7 +470,7 @@ static enum MangleResult mangleOptions(const uint8_t *origData, size_t origDataS
newOffset += config->dhcpOptsSize;
if (config->debug)
- logMessage(LOG_DEBUG, "Inserting END option …\n");
+ logMessage(LOG_DEBUG, "Inserting END option\n");
/* Finally insert the END option: */
newData[newOffset++] = DHCPOPT_END;
@@ -514,7 +518,7 @@ static void writePID(void)
return;
pid_t pid = getpid();
- logMessage(LOG_DEBUG, "Writing PID %ld to %s …\n", (long)pid, config->pidFile);
+ logMessage(LOG_DEBUG, "Writing PID %ld to %s\n", (long)pid, config->pidFile);
FILE *f = fopen(config->pidFile, "w");
if (!f)
@@ -531,7 +535,7 @@ static void removePIDFile(void)
{
if (config->pidFile)
{
- logMessage(LOG_DEBUG, "Removing PID file %s …\n", config->pidFile);
+ logMessage(LOG_DEBUG, "Removing PID file %s\n", config->pidFile);
unlink(config->pidFile);
}
}
@@ -543,7 +547,7 @@ static void destroyConfig(void)
static void initSignalHandler(void)
{
- logMessage(LOG_DEBUG, "Initialising signal handler …\n");
+ logMessage(LOG_DEBUG, "Initialising signal handler\n");
struct sigaction sigAction = { .sa_handler = &setEscapeMainLoopFlag };
@@ -584,7 +588,8 @@ static void debugLogOptions(void)
uint8_t code = config->dhcpOptCodes[i];
bool atEnd = i == config->dhcpOptCodeCount - 1;
const char *delim = atEnd ? "\n" : ", ";
- logMessage(LOG_DEBUG, "0x%02X (%u)%s", code, code, delim);
+ logMessage(LOG_DEBUG, "%u (0x%02X) (%s)%s", code, code, dhcp_optionString(
+ code), delim);
}
}
@@ -617,14 +622,15 @@ static void debugLogPacketHeader(const uint8_t *data, size_t size)
const struct IPAddr *destIP = (const struct IPAddr *)&packet->ipHeader.destAddr;
logMessage(LOG_DEBUG, "Inspecting %zu-byte DHCP packet from "
- "%02X:%02X:%02X:%02X:%02X:%02X to %d.%d.%d.%d …\n",
+ "%02X:%02X:%02X:%02X:%02X:%02X to %d.%d.%d.%d:%d\n",
size,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
- destIP->o1, destIP->o2, destIP->o3, destIP->o4
+ destIP->o1, destIP->o2, destIP->o3, destIP->o4,
+ ntohs(packet->udpHeader.destPort)
);
}
-static void debugLogOption(const struct DHCPOption *option)
+static void debugLogOptionFound(const struct DHCPOption *option)
{
if (option->code == DHCPOPT_PAD)
return;
@@ -632,22 +638,47 @@ static void debugLogOption(const struct DHCPOption *option)
logMessage(LOG_DEBUG,"Found END option %s\n", config->dhcpOptCodeCount ?
"(removing)" : "(copying)");
else if (option->code == DHCPOPT_TYPE && option->length == 1)
- logMessage(LOG_DEBUG, "Found option %hhu (0x%02hhX) (DHCP message type): %s",
+ logMessage(LOG_DEBUG, "Found option %' '3hhu (0x%02hhX) (DHCP message type) %s",
option->code, option->code, dhcp_msgTypeString(option->data[0]));
else
+ debugLogOption("Found", option);
+}
+
+static void debugLogOption(const char *action, const struct DHCPOption *option)
+{
+ /* String buffer for hex string (maximum DHCP option length (256) times
+ * three characters (two digits and a space)) */
+ char optPayload[256 * 3];
+ size_t i = 0;
+ for (; i < option->length; ++i)
+ sprintf(optPayload + 3*i, "%02X ", option->data[i]);
+
+ /* Remove last space: */
+ if (i)
+ optPayload[3*i - 1] = '\0';
+
+ const char *optName = dhcp_optionString(option->code);
+ size_t optNameLen = strlen(optName);
+ const size_t alignedWidth = 24;
+ logMessage(LOG_DEBUG, "%s option %' '3hhu (0x%02hhX) (%s)%*s with %' '3u-byte payload %s",
+ action,
+ option->code,
+ option->code,
+ optName,
+ optNameLen > alignedWidth ? 0 : alignedWidth - optNameLen,
+ "",
+ option->length,
+ optPayload);
+}
+
+static void debugLogInjectedOptions(void)
+{
+ for (size_t offset = 0; offset < config->dhcpOptsSize;)
{
- /* String buffer for hex string (maximum DHCP option length (256) times
- * three characters (two digits and a space)) */
- char optPayload[256 * 3];
- size_t i = 0;
- for (; i < option->length; ++i)
- sprintf(optPayload + 3*i, "%02X ", option->data[i]);
-
- /* Remove last space: */
- if (i)
- optPayload[3*i - 1] = '\0';
-
- logMessage(LOG_DEBUG, "Found option %hhu (0x%02hhX) with %' '3u-byte payload %s",
- option->code, option->code, option->length, optPayload);
+ const struct DHCPOption *option = (const struct DHCPOption *)(&config->dhcpOpts[offset]);
+ debugLogOption("Injecting", option);
+ logMessage(LOG_DEBUG, "%s", "\n");
+ offset += option->code == DHCPOPT_PAD || option->code == DHCPOPT_END ? 1
+ : sizeof(struct DHCPOption) + option->length;
}
}
diff --git a/src/ipv4.h b/src/ipv4.h
index 8b3ee07..00141b4 100644
--- a/src/ipv4.h
+++ b/src/ipv4.h
@@ -24,6 +24,7 @@
#include
#include
+#pragma pack(2)
struct IPv4Header
{
uint8_t verIHL;
@@ -36,7 +37,8 @@ struct IPv4Header
uint16_t checksum;
uint32_t sourceAddr;
uint32_t destAddr;
-} __attribute__((packed));
+};
+#pragma pack()
uint16_t ipv4_checksum(const struct IPv4Header *ipv4Header);
size_t ipv4_headerLen(const struct IPv4Header *ipv4Header);
diff --git a/src/udp.h b/src/udp.h
index 879c483..d3e98c2 100644
--- a/src/udp.h
+++ b/src/udp.h
@@ -22,12 +22,14 @@
#include
+#pragma pack(2)
struct UDPHeader
{
uint16_t sourcePort;
uint16_t destPort;
uint16_t length;
uint16_t checksum;
-} __attribute__((packed));
+};
+#pragma pack()
#endif // DHCPOPTINJ_UDP_H