From fa03879b6f076875cd16313294e943f2102f788a Mon Sep 17 00:00:00 2001 From: Sergey Matveychuk Date: Mon, 15 Apr 2013 20:37:05 +0400 Subject: [PATCH] Reindent. Fix rps_limit. (by lytboris@) --- HISTORY | 3 + dhcp_options.h | 632 ++++++++-------- dhcprelya.c | 1568 ++++++++++++++++++++-------------------- dhcprelya.conf-example | 2 +- dhcprelya.h | 175 +++-- ip_checksum.c | 75 +- log_plugin.c | 904 +++++++++++------------ net_utils.c | 127 ++-- option82_plugin.c | 554 +++++++------- radius_plugin.c | 462 ++++++------ utils.c | 130 ++-- 11 files changed, 2283 insertions(+), 2349 deletions(-) diff --git a/HISTORY b/HISTORY index 6297dd4..2f2fc89 100644 --- a/HISTORY +++ b/HISTORY @@ -1,3 +1,6 @@ +2013-04-15: + 4.6 version + * fix rps_limit converting it to per-interface basis (and removing mutex) 2012-12-03: 4.5 version * destroy() in plugins for smooth shutdown. diff --git a/dhcp_options.h b/dhcp_options.h index d5653ab..d5d0919 100644 --- a/dhcp_options.h +++ b/dhcp_options.h @@ -1,347 +1,341 @@ -/* - * this list was stolen from The DHCP Handbook by Droms and Lemon, Appendix D - */ +/* this list was stolen from The DHCP Handbook by Droms and Lemon, Appendix D */ /* The first comment is the number, the last parameter is if it's verbosed */ const char *dhcp_options[] = { -/* 0 */ "pad", -/* 1 */ "Subnet mask", /**/ -/* 2 */ "Time offset", /**/ -/* 3 */ "Routers", /**/ -/* 4 */ "Time server", /**/ -/* 5 */ "Name server", /**/ -/* 6 */ "DNS server", /**/ -/* 7 */ "Log server", /**/ -/* 8 */ "Cookie server", /**/ -/* 9 */ "LPR server", /**/ -/* 10 */ "Impress server", /**/ -/* 11 */ "Resource location server", /**/ -/* 12 */ "Host name", /**/ -/* 13 */ "Boot file size", /**/ -/* 14 */ "Merit dump file", /**/ -/* 15 */ "Domainname", /**/ -/* 16 */ "Swap server", /**/ -/* 17 */ "Root path", /**/ -/* 18 */ "Extensions path", /**/ -/* 19 */ "IP forwarding", /**/ -/* 20 */ "Non-local source routing", /**/ -/* 21 */ "Policy filter", /**/ -/* 22 */ "Maximum datagram reassembly size", /**/ -/* 23 */ "Default IP TTL", /**/ -/* 24 */ "Path MTU aging timeout", /**/ -/* 25 */ "Path MTU plateau table", /**/ -/* 26 */ "Interface MTU", /**/ -/* 27 */ "All subnets local", /**/ -/* 28 */ "Broadcast address", /**/ -/* 29 */ "Perform mask discovery", /**/ -/* 30 */ "Mask supplier", /**/ -/* 31 */ "Perform router discovery", /**/ -/* 32 */ "Router solicitation", /**/ -/* 33 */ "Static route", /**/ -/* 34 */ "Trailer encapsulation", /**/ -/* 35 */ "ARP cache timeout", /**/ -/* 36 */ "Ethernet encapsulation", /**/ -/* 37 */ "TCP default TTL", /**/ -/* 38 */ "TCP keepalive interval", /**/ -/* 39 */ "TCP keepalive garbage", /**/ -/* 40 */ "NIS domain", /**/ -/* 41 */ "NIS servers", /**/ -/* 42 */ "NTP servers", /**/ -/* 43 */ "Vendor specific info", /**/ -/* 44 */ "NetBIOS name server", /**/ -/* 45 */ "NetBIOS datagram distribution server", /**/ -/* 46 */ "NetBIOS node type", /**/ -/* 47 */ "NetBIOS scope", /**/ -/* 48 */ "X Window System font server", /**/ -/* 49 */ "X Window System display server", /**/ -/* 50 */ "Request IP address", /**/ -/* 51 */ "IP address leasetime", /**/ -/* 52 */ "Option overload", /**/ -/* 53 */ "DHCP message type", /**/ -/* 54 */ "Server identifier", /**/ -/* 55 */ "Parameter Request List", /**/ -/* 56 */ "Message", /**/ -/* 57 */ "Maximum DHCP message size", /**/ -/* 58 */ "T1", /**/ -/* 59 */ "T2", /**/ -/* 60 */ "Vendor class identifier", /**/ -/* 61 */ "Client-identifier", /**/ -/* 62 */ "Netware/IP domain name", /**/ -/* 63 */ "Netware/IP domain information", /**/ -/* 64 */ "NIS+ domain", /**/ -/* 65 */ "NIS+ servers", /**/ -/* 66 */ "TFTP server name", /**/ -/* 67 */ "Bootfile name", /**/ -/* 68 */ "Mobile IP home agent", /**/ -/* 69 */ "SMTP server", /**/ -/* 70 */ "POP3 server", /**/ -/* 71 */ "NNTP server", /**/ -/* 72 */ "WWW server", /**/ -/* 73 */ "Finger server", /**/ -/* 74 */ "IRC server", /**/ -/* 75 */ "StreetTalk server", /**/ -/* 76 */ "StreetTalk directory assistance server", /**/ -/* 77 */ "User-class Identification", -/* 78 */ "SLP-directory-agent", -/* 79 */ "SLP-service-scope", -/* 80 */ "Naming Authority", -/* 81 */ "Client FQDN", /**/ -/* 82 */ "Relay Agent Information", -/* 83 */ "Agent Remote ID", -/* 84 */ "Agent Subnet Mask", -/* 85 */ "NDS server", /**/ -/* 86 */ "NDS tree name", /**/ -/* 87 */ "NDS context", /**/ -/* 88 */ "IEEE 1003.1 POSIX", -/* 89 */ "FQDN", -/* 90 */ "Authentication", -/* 91 */ "Vines TCP/IP", -/* 92 */ "Server Selection", -/* 93 */ "Client System", -/* 94 */ "Client NDI", -/* 95 */ "LDAP", -/* 96 */ "IPv6 Transitions", -/* 97 */ "UUID/GUID", -/* 98 */ "UPA servers", -/* 99 */ "???", -/* 100 */ "Printer Name", -/* 101 */ "MDHCP", -/* 102 */ "???", -/* 103 */ "???", -/* 104 */ "???", -/* 105 */ "???", -/* 106 */ "???", -/* 107 */ "???", -/* 108 */ "Swap Path", -/* 109 */ "???", -/* 110 */ "IPX Compatability", -/* 111 */ "???", -/* 112 */ "Netinfo Address", -/* 113 */ "Netinfo Tag", -/* 114 */ "URL", -/* 115 */ "DHCP Failover", -/* 116 */ "DHCP Autoconfiguration", -/* 117 */ "Name Service Search", -/* 118 */ "Subnet selection", -/* 119 */ "Domain Search", -/* 120 */ "SIP Servers DHCP Option", -/* 121 */ "Classless Static Route", -/* 122 */ "???", -/* 123 */ "???", -/* 124 */ "???", -/* 125 */ "???", -/* 126 */ "Extension", -/* 127 */ "Extension", -/* 128 */ "???", -/* 129 */ "???", -/* 130 */ "???", -/* 131 */ "???", -/* 132 */ "???", -/* 133 */ "???", -/* 134 */ "???", -/* 135 */ "???", -/* 136 */ "???", -/* 137 */ "???", -/* 138 */ "???", -/* 139 */ "???", -/* 140 */ "???", -/* 141 */ "???", -/* 142 */ "???", -/* 143 */ "???", -/* 144 */ "HP - TFTP file", -/* 145 */ "???", -/* 146 */ "???", -/* 147 */ "???", -/* 148 */ "???", -/* 149 */ "???", -/* 150 */ "CiscoCallManagerTFTP", -/* 151 */ "???", -/* 152 */ "???", -/* 153 */ "???", -/* 154 */ "???", -/* 155 */ "???", -/* 156 */ "???", -/* 157 */ "???", -/* 158 */ "???", -/* 159 */ "???", -/* 160 */ "???", -/* 161 */ "???", -/* 162 */ "???", -/* 163 */ "???", -/* 164 */ "???", -/* 165 */ "???", -/* 166 */ "???", -/* 167 */ "???", -/* 168 */ "???", -/* 169 */ "???", -/* 170 */ "???", -/* 171 */ "???", -/* 172 */ "???", -/* 173 */ "???", -/* 174 */ "???", -/* 175 */ "???", -/* 176 */ "???", -/* 177 */ "???", -/* 178 */ "???", -/* 179 */ "???", -/* 180 */ "???", -/* 181 */ "???", -/* 182 */ "???", -/* 183 */ "???", -/* 184 */ "???", -/* 185 */ "???", -/* 186 */ "???", -/* 187 */ "???", -/* 188 */ "???", -/* 189 */ "???", -/* 190 */ "???", -/* 191 */ "???", -/* 192 */ "???", -/* 193 */ "???", -/* 194 */ "???", -/* 195 */ "???", -/* 196 */ "???", -/* 197 */ "???", -/* 198 */ "???", -/* 199 */ "???", -/* 200 */ "???", -/* 201 */ "???", -/* 202 */ "???", -/* 203 */ "???", -/* 204 */ "???", -/* 205 */ "???", -/* 206 */ "???", -/* 207 */ "???", -/* 208 */ "???", -/* 209 */ "???", -/* 210 */ "Authenticate", -/* 211 */ "???", -/* 212 */ "???", -/* 213 */ "???", -/* 214 */ "???", -/* 215 */ "???", -/* 216 */ "???", -/* 217 */ "???", -/* 218 */ "???", -/* 219 */ "???", -/* 220 */ "???", -/* 221 */ "???", -/* 222 */ "???", -/* 223 */ "???", -/* 224 */ "???", -/* 225 */ "???", -/* 226 */ "???", -/* 227 */ "???", -/* 228 */ "???", -/* 229 */ "???", -/* 230 */ "???", -/* 231 */ "???", -/* 232 */ "???", -/* 233 */ "???", -/* 234 */ "???", -/* 235 */ "???", -/* 236 */ "???", -/* 237 */ "???", -/* 238 */ "???", -/* 239 */ "???", -/* 240 */ "???", -/* 241 */ "???", -/* 242 */ "???", -/* 243 */ "???", -/* 244 */ "???", -/* 245 */ "???", -/* 246 */ "???", -/* 247 */ "???", -/* 248 */ "???", -/* 249 */ "MSFT - Classless route", -/* 250 */ "???", -/* 251 */ "???", -/* 252 */ "MSFT - WinSock Proxy Auto Detect", -/* 253 */ "???", -/* 254 */ "???", -/* 255 */ "End"}; + /* 0 */ "pad", + /* 1 */ "Subnet mask", /**/ + /* 2 */ "Time offset", /**/ + /* 3 */ "Routers", /**/ + /* 4 */ "Time server", /**/ + /* 5 */ "Name server", /**/ + /* 6 */ "DNS server", /**/ + /* 7 */ "Log server", /**/ + /* 8 */ "Cookie server", /**/ + /* 9 */ "LPR server", /**/ + /* 10 */ "Impress server", /**/ + /* 11 */ "Resource location server", /**/ + /* 12 */ "Host name", /**/ + /* 13 */ "Boot file size", /**/ + /* 14 */ "Merit dump file", /**/ + /* 15 */ "Domainname", /**/ + /* 16 */ "Swap server",/**/ + /* 17 */ "Root path", /**/ + /* 18 */ "Extensions path", /**/ + /* 19 */ "IP forwarding", /**/ + /* 20 */ "Non-local source routing", /**/ + /* 21 */ "Policy filter", /**/ + /* 22 */ "Maximum datagram reassembly size", /**/ + /* 23 */ "Default IP TTL", /**/ + /* 24 */ "Path MTU aging timeout", /**/ + /* 25 */ "Path MTU plateau table", /**/ + /* 26 */ "Interface MTU", /**/ + /* 27 */ "All subnets local", /**/ + /* 28 */ "Broadcast address", /**/ + /* 29 */ "Perform mask discovery", /**/ + /* 30 */ "Mask supplier", /**/ + /* 31 */ "Perform router discovery", /**/ + /* 32 */ "Router solicitation", /**/ + /* 33 */ "Static route", /**/ + /* 34 */ "Trailer encapsulation", /**/ + /* 35 */ "ARP cache timeout", /**/ + /* 36 */ "Ethernet encapsulation", /**/ + /* 37 */ "TCP default TTL", /**/ + /* 38 */ "TCP keepalive interval", /**/ + /* 39 */ "TCP keepalive garbage", /**/ + /* 40 */ "NIS domain", /**/ + /* 41 */ "NIS servers",/**/ + /* 42 */ "NTP servers",/**/ + /* 43 */ "Vendor specific info", /**/ + /* 44 */ "NetBIOS name server", /**/ + /* 45 */ "NetBIOS datagram distribution server", /**/ + /* 46 */ "NetBIOS node type", /**/ + /* 47 */ "NetBIOS scope", /**/ + /* 48 */ "X Window System font server", /**/ + /* 49 */ "X Window System display server", /**/ + /* 50 */ "Request IP address", /**/ + /* 51 */ "IP address leasetime", /**/ + /* 52 */ "Option overload", /**/ + /* 53 */ "DHCP message type", /**/ + /* 54 */ "Server identifier", /**/ + /* 55 */ "Parameter Request List", /**/ + /* 56 */ "Message", /**/ + /* 57 */ "Maximum DHCP message size", /**/ + /* 58 */ "T1", /**/ + /* 59 */ "T2", /**/ + /* 60 */ "Vendor class identifier", /**/ + /* 61 */ "Client-identifier", /**/ + /* 62 */ "Netware/IP domain name", /**/ + /* 63 */ "Netware/IP domain information", /**/ + /* 64 */ "NIS+ domain",/**/ + /* 65 */ "NIS+ servers", /**/ + /* 66 */ "TFTP server name", /**/ + /* 67 */ "Bootfile name", /**/ + /* 68 */ "Mobile IP home agent", /**/ + /* 69 */ "SMTP server",/**/ + /* 70 */ "POP3 server",/**/ + /* 71 */ "NNTP server",/**/ + /* 72 */ "WWW server", /**/ + /* 73 */ "Finger server", /**/ + /* 74 */ "IRC server", /**/ + /* 75 */ "StreetTalk server", /**/ + /* 76 */ "StreetTalk directory assistance server", /**/ + /* 77 */ "User-class Identification", + /* 78 */ "SLP-directory-agent", + /* 79 */ "SLP-service-scope", + /* 80 */ "Naming Authority", + /* 81 */ "Client FQDN",/**/ + /* 82 */ "Relay Agent Information", + /* 83 */ "Agent Remote ID", + /* 84 */ "Agent Subnet Mask", + /* 85 */ "NDS server", /**/ + /* 86 */ "NDS tree name", /**/ + /* 87 */ "NDS context",/**/ + /* 88 */ "IEEE 1003.1 POSIX", + /* 89 */ "FQDN", + /* 90 */ "Authentication", + /* 91 */ "Vines TCP/IP", + /* 92 */ "Server Selection", + /* 93 */ "Client System", + /* 94 */ "Client NDI", + /* 95 */ "LDAP", + /* 96 */ "IPv6 Transitions", + /* 97 */ "UUID/GUID", + /* 98 */ "UPA servers", + /* 99 */ "???", + /* 100 */ "Printer Name", + /* 101 */ "MDHCP", + /* 102 */ "???", + /* 103 */ "???", + /* 104 */ "???", + /* 105 */ "???", + /* 106 */ "???", + /* 107 */ "???", + /* 108 */ "Swap Path", + /* 109 */ "???", + /* 110 */ "IPX Compatability", + /* 111 */ "???", + /* 112 */ "Netinfo Address", + /* 113 */ "Netinfo Tag", + /* 114 */ "URL", + /* 115 */ "DHCP Failover", + /* 116 */ "DHCP Autoconfiguration", + /* 117 */ "Name Service Search", + /* 118 */ "Subnet selection", + /* 119 */ "Domain Search", + /* 120 */ "SIP Servers DHCP Option", + /* 121 */ "Classless Static Route", + /* 122 */ "???", + /* 123 */ "???", + /* 124 */ "???", + /* 125 */ "???", + /* 126 */ "Extension", + /* 127 */ "Extension", + /* 128 */ "???", + /* 129 */ "???", + /* 130 */ "???", + /* 131 */ "???", + /* 132 */ "???", + /* 133 */ "???", + /* 134 */ "???", + /* 135 */ "???", + /* 136 */ "???", + /* 137 */ "???", + /* 138 */ "???", + /* 139 */ "???", + /* 140 */ "???", + /* 141 */ "???", + /* 142 */ "???", + /* 143 */ "???", + /* 144 */ "HP - TFTP file", + /* 145 */ "???", + /* 146 */ "???", + /* 147 */ "???", + /* 148 */ "???", + /* 149 */ "???", + /* 150 */ "CiscoCallManagerTFTP", + /* 151 */ "???", + /* 152 */ "???", + /* 153 */ "???", + /* 154 */ "???", + /* 155 */ "???", + /* 156 */ "???", + /* 157 */ "???", + /* 158 */ "???", + /* 159 */ "???", + /* 160 */ "???", + /* 161 */ "???", + /* 162 */ "???", + /* 163 */ "???", + /* 164 */ "???", + /* 165 */ "???", + /* 166 */ "???", + /* 167 */ "???", + /* 168 */ "???", + /* 169 */ "???", + /* 170 */ "???", + /* 171 */ "???", + /* 172 */ "???", + /* 173 */ "???", + /* 174 */ "???", + /* 175 */ "???", + /* 176 */ "???", + /* 177 */ "???", + /* 178 */ "???", + /* 179 */ "???", + /* 180 */ "???", + /* 181 */ "???", + /* 182 */ "???", + /* 183 */ "???", + /* 184 */ "???", + /* 185 */ "???", + /* 186 */ "???", + /* 187 */ "???", + /* 188 */ "???", + /* 189 */ "???", + /* 190 */ "???", + /* 191 */ "???", + /* 192 */ "???", + /* 193 */ "???", + /* 194 */ "???", + /* 195 */ "???", + /* 196 */ "???", + /* 197 */ "???", + /* 198 */ "???", + /* 199 */ "???", + /* 200 */ "???", + /* 201 */ "???", + /* 202 */ "???", + /* 203 */ "???", + /* 204 */ "???", + /* 205 */ "???", + /* 206 */ "???", + /* 207 */ "???", + /* 208 */ "???", + /* 209 */ "???", + /* 210 */ "Authenticate", + /* 211 */ "???", + /* 212 */ "???", + /* 213 */ "???", + /* 214 */ "???", + /* 215 */ "???", + /* 216 */ "???", + /* 217 */ "???", + /* 218 */ "???", + /* 219 */ "???", + /* 220 */ "???", + /* 221 */ "???", + /* 222 */ "???", + /* 223 */ "???", + /* 224 */ "???", + /* 225 */ "???", + /* 226 */ "???", + /* 227 */ "???", + /* 228 */ "???", + /* 229 */ "???", + /* 230 */ "???", + /* 231 */ "???", + /* 232 */ "???", + /* 233 */ "???", + /* 234 */ "???", + /* 235 */ "???", + /* 236 */ "???", + /* 237 */ "???", + /* 238 */ "???", + /* 239 */ "???", + /* 240 */ "???", + /* 241 */ "???", + /* 242 */ "???", + /* 243 */ "???", + /* 244 */ "???", + /* 245 */ "???", + /* 246 */ "???", + /* 247 */ "???", + /* 248 */ "???", + /* 249 */ "MSFT - Classless route", + /* 250 */ "???", + /* 251 */ "???", + /* 252 */ "MSFT - WinSock Proxy Auto Detect", + /* 253 */ "???", + /* 254 */ "???", + /* 255 */ "End"}; const char *dhcp_message_types[] = { - "wrong specified", -/* 1 */ "DHCPDISCOVER", -/* 2 */ "DHCPOFFER", -/* 3 */ "DHCPREQUEST", -/* 4 */ "DHCPDECLINE", -/* 5 */ "DHCPACK", -/* 6 */ "DHCPNAK", -/* 7 */ "DHCPRELEASE", -/* 8 */ "DHCPINFORM" + "wrong specified", + /* 1 */ "DHCPDISCOVER", + /* 2 */ "DHCPOFFER", + /* 3 */ "DHCPREQUEST", + /* 4 */ "DHCPDECLINE", + /* 5 */ "DHCPACK", + /* 6 */ "DHCPNAK", + /* 7 */ "DHCPRELEASE", + /* 8 */ "DHCPINFORM" }; const char *netbios_node_type[] = { -/* 0 */ "none", -/* 1 */ "B-node", -/* 2 */ "P-node", -/* 3 */ "", -/* 4 */ "M-node", -/* 5 */ "", -/* 6 */ "", -/* 7 */ "", -/* 8 */ "H-node" + /* 0 */ "none", + /* 1 */ "B-node", + /* 2 */ "P-node", + /* 3 */ "", + /* 4 */ "M-node", + /* 5 */ "", + /* 6 */ "", + /* 7 */ "", + /* 8 */ "H-node" }; const char *option_overload[] = { -/* 0 **/ "unspecified", -/* 1 */ "file field holds options", -/* 2 */ "sname field holds options", -/* 3 */ "file and sname field holds options" + /* 0 * */ "unspecified", + /* 1 */ "file field holds options", + /* 2 */ "sname field holds options", + /* 3 */ "file and sname field holds options" }; const char *enabledisable[] = { -/* 0 */ "disabled", -/* 1 */ "enabled" + /* 0 */ "disabled", + /* 1 */ "enabled" }; const char *ethernet_encapsulation[] = { -/* 0 */ "Ethernet version 2", -/* 1 */ "IEEE 802.3" + /* 0 */ "Ethernet version 2", + /* 1 */ "IEEE 802.3" }; const char *operands[] = { -/* 0 */ "wrong specified", -/* 1 */ "BOOTPREQUEST", -/* 2 */ "BOOTPREPLY" + /* 0 */ "wrong specified", + /* 1 */ "BOOTPREQUEST", + /* 2 */ "BOOTPREPLY" }; -/* - * From RFC 3046 - */ +/* From RFC 3046 */ const char *relayagent_suboptions[] = { -/* 0 */ "", -/* 1 */ "Circuit-ID", -/* 2 */ "Remote-ID" + /* 0 */ "", + /* 1 */ "Circuit-ID", + /* 2 */ "Remote-ID" }; -/* - * Copied from RFC1700 - */ +/* Copied from RFC1700 */ const char *htypes[] = { -/* 0 */ "wrong specified", -/* 1 */ "Ethernet", -/* 2 */ "Experimental Ethernet", -/* 3 */ "Amateur Radio AX.25", -/* 4 */ "Proteon ProNET Token Ring", -/* 5 */ "Chaos", -/* 6 */ "IEEE 802 Networks", -/* 7 */ "ARCNET", -/* 8 */ "Hyperchannel", -/* 9 */ "Lanstar", -/* 10 */ "Autonet Short Address", -/* 11 */ "LocalTalk", -/* 12 */ "LocalNet", -/* 13 */ "Ultra link", -/* 14 */ "SMDS", -/* 15 */ "Frame Relay", -/* 16 */ "ATM", -/* 17 */ "HDLC", -/* 18 */ "Fibre Channel", -/* 19 */ "ATM", -/* 20 */ "Serial Line", -/* 21 */ "ATM" + /* 0 */ "wrong specified", + /* 1 */ "Ethernet", + /* 2 */ "Experimental Ethernet", + /* 3 */ "Amateur Radio AX.25", + /* 4 */ "Proteon ProNET Token Ring", + /* 5 */ "Chaos", + /* 6 */ "IEEE 802 Networks", + /* 7 */ "ARCNET", + /* 8 */ "Hyperchannel", + /* 9 */ "Lanstar", + /* 10 */ "Autonet Short Address", + /* 11 */ "LocalTalk", + /* 12 */ "LocalNet", + /* 13 */ "Ultra link", + /* 14 */ "SMDS", + /* 15 */ "Frame Relay", + /* 16 */ "ATM", + /* 17 */ "HDLC", + /* 18 */ "Fibre Channel", + /* 19 */ "ATM", + /* 20 */ "Serial Line", + /* 21 */ "ATM" }; diff --git a/dhcprelya.c b/dhcprelya.c index 54e3de0..389e089 100644 --- a/dhcprelya.c +++ b/dhcprelya.c @@ -1,31 +1,28 @@ -/* - * Copyright (c) 2007-2012 Sergey Matveychuk - * Yandex, LLC. All rights reserved. - * +/* Copyright (c) 2007-2012 Sergey Matveychuk Yandex, LLC. All rights + * reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 4. Neither the name + * of the company nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ + * SUCH DAMAGE. */ #include #include @@ -53,886 +50,867 @@ #include "dhcprelya.h" -#define VERSION "4.5" +#define VERSION "4.6" /* options */ /* globals (can check in modules) */ -unsigned debug=0, max_packet_size=1400;; +unsigned debug = 0, max_packet_size = 1400;; /* local */ -static unsigned max_hops=4; +static unsigned max_hops = 4; static char plugin_base[80]; -uint8_t plugins_number=0; +uint8_t plugins_number = 0; struct plugin_data *plugins[MAX_PLUGINS]; -struct pidfh *pfh=NULL; +struct pidfh *pfh = NULL; int bootps_port, bootpc_port; struct interface *ifs[IF_MAX]; struct dhcp_server *servers[SERVERS_MAX]; -int if_num=0; /* interfaces number */ -int srv_num=0; /* servers number */ -unsigned int queue_size=0, rps_limit=0; +int if_num = 0; /* interfaces number */ +int srv_num = 0; /* servers number */ +unsigned int queue_size = 0, rps_limit = 0; pthread_mutex_t queue_lock; plugin_options_head_t *options_heads[MAX_PLUGINS]; -pthread_mutex_t last_pkt_lock; -struct timeval last_pkt = { 0, 0 }; -#define DeltaUSec(t1,t2) \ - ( ((double)t1.tv_sec * 1000000.0 + (double)t1.tv_usec) \ - - ((double)t2.tv_sec * 1000000.0 + (double)t2.tv_usec) ) +#define DeltaUSec(finish,start) \ + (long)( ((long)(finish.tv_sec - start.tv_sec)<<10) + (long)(finish.tv_nsec>>20) - (long)(start.tv_nsec>>20) ) void usage(char *prgname) { - fprintf(stderr, "DHCP relay. Yandex edition. 2007-2012.\n"); - fprintf(stderr, "Version %s.\n", VERSION); - fprintf(stderr, "Usage:\n%s [-d] [-p] -f \n", prgname); - fprintf(stderr, "or ISC compatible mode:\n%s [-d] [-p] -A -c -i ... ...\n", prgname); - exit(EX_OK); + fprintf(stderr, "DHCP relay. Yandex edition. 2007-2012.\n"); + fprintf(stderr, "Version %s.\n", VERSION); + fprintf(stderr, "Usage:\n%s [-d] [-p] -f \n", prgname); + fprintf(stderr, "or ISC compatible mode:\n%s [-d] [-p] -A -c -i ... ...\n", prgname); + exit(EX_OK); } void -process_error(int ret_code, char *fmt, ...) +process_error(int ret_code, char *fmt,...) { - va_list ap; - char buf[1024]; + va_list ap; + char buf[1024]; - va_start(ap, fmt); + va_start(ap, fmt); - if(pfh) - pidfile_remove(pfh); + if (pfh) + pidfile_remove(pfh); - vsprintf(buf, fmt, ap); - logd(LOG_ERR, buf); - errx(ret_code, buf); + vsprintf(buf, fmt, ap); + logd(LOG_ERR, buf); + errx(ret_code, buf); - /* does not reach */ - va_end(ap); + /* does not reach */ + va_end(ap); } int find_interface(ip_addr_t addr) { - int i; + int i; - for(i=0; iip) - break; - } + for (i = 0; i < if_num; i++) { + if (addr == ifs[i]->ip) + break; + } - return i; + return i; } int open_interface(char *iname) { - int i, j, x=1; - struct ifreq ifr; - struct bpf_program fp; - struct sockaddr_in baddr; - char errbuf[PCAP_ERRBUF_SIZE], file[32], buf[256]; - - if(if_num >= IF_MAX-1) - process_error(EX_RES, "too many interfaces"); - - logd(LOG_DEBUG, "Trying to open interface: %s", iname); - - /* If we already have the interface, bind to the current server then */ - for(i=0; i < if_num; i++) { - if(strcmp(ifs[i]->name, iname) == 0) { - /* If the interface is already binded to this - * server (appears twice). Ignore it. - */ - if(ifs[i]->srv_num != srv_num) { - ifs[i]->srv_num++; - ifs[i]->srvrs = realloc(ifs[i]->srvrs, ifs[i]->srv_num*sizeof(int)); - ifs[i]->srvrs[ifs[i]->srv_num-1] = srv_num-1; - } - return 1; + int i, j, x = 1; + struct ifreq ifr; + struct bpf_program fp; + struct sockaddr_in baddr; + char errbuf[PCAP_ERRBUF_SIZE], file[32], buf[256]; + + if (if_num >= IF_MAX - 1) + process_error(EX_RES, "too many interfaces"); + + logd(LOG_DEBUG, "Trying to open interface: %s", iname); + + /* If we already have the interface, bind to the current server then */ + for (i = 0; i < if_num; i++) { + if (strcmp(ifs[i]->name, iname) == 0) { + /* If the interface is already binded to this server + * (appears twice). Ignore it. */ + if (ifs[i]->srv_num != srv_num) { + ifs[i]->srv_num++; + ifs[i]->srvrs = realloc(ifs[i]->srvrs, ifs[i]->srv_num * sizeof(int)); + ifs[i]->srvrs[ifs[i]->srv_num - 1] = srv_num - 1; + } + return 1; + } } - } - - ifs[if_num] = malloc(sizeof(struct interface)); - if(ifs[if_num] == NULL) - process_error(EX_MEM, "malloc"); - - ifs[if_num]->idx = if_num; - strlcpy(ifs[if_num]->name, iname, INTF_NAME_LEN); - - if(!get_mac(iname, (char*)ifs[if_num]->mac) || - !get_ip(iname, &ifs[if_num]->ip, &ifs[if_num]->mask)) { - free(ifs[if_num]); - return 0; - } - - ifs[i]->srv_num = 1; - ifs[i]->srvrs = malloc(ifs[i]->srv_num*sizeof(int)); - if(ifs[i]->srvrs == NULL) - process_error(EX_MEM, "malloc"); - ifs[i]->srvrs[0] = srv_num-1; - - /* Looking for a free BPF device and open it */ - for (j = 0; j < 255; j++) { - snprintf(file, sizeof(file), "/dev/bpf%d", j); - ifs[if_num]->bpf = open(file, O_WRONLY); - if(ifs[if_num]->bpf != -1 || errno != EBUSY) - break; - } - /* Bind BPF to an interface */ - bzero(&ifr, sizeof(ifr)); - strlcpy(ifr.ifr_name, iname, sizeof(ifr.ifr_name)); - if(ioctl(ifs[if_num]->bpf, BIOCSETIF, (char *)&ifr) < 0) - process_error(EX_RES, "Can't BIOCSETIF"); - - if((ifs[if_num]->cap = pcap_open_live(iname, max_packet_size, 0, 100, errbuf)) == NULL) - process_error(EX_RES, "pcap_open_live(%s): %s", iname, errbuf); - if(pcap_compile(ifs[if_num]->cap, &fp, "udp and dst port bootps", 0, 0) < 0) - process_error(EX_RES, "pcap_compile"); - if(pcap_setfilter(ifs[if_num]->cap, &fp) < 0) - process_error(EX_RES, "pcap_setfilter"); - - if((ifs[if_num]->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) - process_error(EX_RES, "socket for listener at %s: %s", iname, strerror(errno)); - - if(setsockopt(ifs[if_num]->fd, SOL_SOCKET, SO_BROADCAST, (char *)&x, sizeof(x)) < 0) - process_error(EX_RES, "setsockopt: SO_BROADCAST"); - if(setsockopt(ifs[if_num]->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&x, sizeof(x)) < 0) - process_error(EX_RES, "setsockopt: SO_REUSEADDR"); - - bzero(&baddr, sizeof(baddr)); - baddr.sin_family = AF_INET; - baddr.sin_port = bootps_port; - memcpy(&baddr.sin_addr.s_addr, &ifs[if_num]->ip, sizeof(ip_addr_t)); - if(bind(ifs[if_num]->fd, (struct sockaddr*)&baddr, sizeof(baddr)) < 0) - process_error(EX_RES, "bind: %s", strerror(errno)); - - logd(LOG_WARNING, "Listen at %s: %s/%s, %s", iname, print_ip(ifs[if_num]->ip, buf), - print_ip(ifs[if_num]->mask, buf+16), print_mac(ifs[if_num]->mac, buf+32)); - - if_num++; - return 1; + + ifs[if_num] = malloc(sizeof(struct interface)); + if (ifs[if_num] == NULL) + process_error(EX_MEM, "malloc"); + + ifs[if_num]->idx = if_num; + strlcpy(ifs[if_num]->name, iname, INTF_NAME_LEN); + + if (!get_mac(iname, (char *)ifs[if_num]->mac) || + !get_ip(iname, &ifs[if_num]->ip, &ifs[if_num]->mask)) { + free(ifs[if_num]); + return 0; + } + ifs[i]->srv_num = 1; + ifs[i]->srvrs = malloc(ifs[i]->srv_num * sizeof(int)); + if (ifs[i]->srvrs == NULL) + process_error(EX_MEM, "malloc"); + ifs[i]->srvrs[0] = srv_num - 1; + + /* Looking for a free BPF device and open it */ + for (j = 0; j < 255; j++) { + snprintf(file, sizeof(file), "/dev/bpf%d", j); + ifs[if_num]->bpf = open(file, O_WRONLY); + if (ifs[if_num]->bpf != -1 || errno != EBUSY) + break; + } + /* Bind BPF to an interface */ + bzero(&ifr, sizeof(ifr)); + strlcpy(ifr.ifr_name, iname, sizeof(ifr.ifr_name)); + if (ioctl(ifs[if_num]->bpf, BIOCSETIF, (char *)&ifr) < 0) + process_error(EX_RES, "Can't BIOCSETIF"); + + if ((ifs[if_num]->cap = pcap_open_live(iname, max_packet_size, 0, 100, errbuf)) == NULL) + process_error(EX_RES, "pcap_open_live(%s): %s", iname, errbuf); + if (pcap_compile(ifs[if_num]->cap, &fp, "udp and dst port bootps", 0, 0) < 0) + process_error(EX_RES, "pcap_compile"); + if (pcap_setfilter(ifs[if_num]->cap, &fp) < 0) + process_error(EX_RES, "pcap_setfilter"); + + if ((ifs[if_num]->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + process_error(EX_RES, "socket for listener at %s: %s", iname, strerror(errno)); + + if (setsockopt(ifs[if_num]->fd, SOL_SOCKET, SO_BROADCAST, (char *)&x, sizeof(x)) < 0) + process_error(EX_RES, "setsockopt: SO_BROADCAST"); + if (setsockopt(ifs[if_num]->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&x, sizeof(x)) < 0) + process_error(EX_RES, "setsockopt: SO_REUSEADDR"); + + bzero(&baddr, sizeof(baddr)); + baddr.sin_family = AF_INET; + baddr.sin_port = bootps_port; + memcpy(&baddr.sin_addr.s_addr, &ifs[if_num]->ip, sizeof(ip_addr_t)); + if (bind(ifs[if_num]->fd, (struct sockaddr *)&baddr, sizeof(baddr)) < 0) + process_error(EX_RES, "bind: %s", strerror(errno)); + + logd(LOG_WARNING, "Listen at %s: %s/%s, %s", iname, print_ip(ifs[if_num]->ip, buf), + print_ip(ifs[if_num]->mask, buf + 16), print_mac(ifs[if_num]->mac, buf + 32)); + + if_num++; + return 1; } int open_server(char *server_spec) { - struct hostent *hostent; - char buf[16], *p; - int port = bootps_port; - char *name = strdup(server_spec); - - if(name == NULL) - process_error(EX_MEM, "malloc"); + struct hostent *hostent; + char buf[16], *p; + int port = bootps_port; + char *name = strdup(server_spec); - if(srv_num >= SERVERS_MAX-1) - process_error(EX_RES, "too many servers"); + if (name == NULL) + process_error(EX_MEM, "malloc"); - logd(LOG_DEBUG, "Open server: %s", name); + if (srv_num >= SERVERS_MAX - 1) + process_error(EX_RES, "too many servers"); - if((p = strchr(name, ':')) != NULL) { - *p = '\0'; - port = htons(atoi(p+1)); - if(port == 0) - process_error(EX_USAGE, "bad port number"); - } + logd(LOG_DEBUG, "Open server: %s", name); - if((hostent = gethostbyname(name)) == NULL) { - free(name); - return 0; - } - - servers[srv_num] = malloc(sizeof(struct dhcp_server)); - if(servers[srv_num] == NULL) - process_error(EX_MEM, "malloc"); + if ((p = strchr(name, ':')) != NULL) { + *p = '\0'; + port = htons(atoi(p + 1)); + if (port == 0) + process_error(EX_USAGE, "bad port number"); + } + if ((hostent = gethostbyname(name)) == NULL) { + free(name); + return 0; + } + servers[srv_num] = malloc(sizeof(struct dhcp_server)); + if (servers[srv_num] == NULL) + process_error(EX_MEM, "malloc"); - servers[srv_num]->name = malloc(strlen(name)); - if(servers[srv_num]->name == NULL) - process_error(EX_MEM, "malloc"); - strlcpy(servers[srv_num]->name, name, sizeof(servers[srv_num]->name)); + servers[srv_num]->name = malloc(strlen(name)); + if (servers[srv_num]->name == NULL) + process_error(EX_MEM, "malloc"); + strlcpy(servers[srv_num]->name, name, sizeof(servers[srv_num]->name)); - bzero(&servers[srv_num]->sockaddr, sizeof(struct sockaddr_in)); - servers[srv_num]->sockaddr.sin_family = AF_INET; - servers[srv_num]->sockaddr.sin_port = port; - memcpy(&(servers[srv_num]->sockaddr.sin_addr.s_addr), hostent->h_addr, hostent->h_length); + bzero(&servers[srv_num]->sockaddr, sizeof(struct sockaddr_in)); + servers[srv_num]->sockaddr.sin_family = AF_INET; + servers[srv_num]->sockaddr.sin_port = port; + memcpy(&(servers[srv_num]->sockaddr.sin_addr.s_addr), hostent->h_addr, hostent->h_length); - srv_num++; + srv_num++; - logd(LOG_WARNING, "DHCP server #%d: %s (%s)", srv_num, name, - print_ip(servers[srv_num-1]->sockaddr.sin_addr.s_addr, buf)); + logd(LOG_WARNING, "DHCP server #%d: %s (%s)", srv_num, name, + print_ip(servers[srv_num - 1]->sockaddr.sin_addr.s_addr, buf)); - free(name); - return 1; + free(name); + return 1; } int sanity_check(const char *packet, unsigned len) { - struct ether_header *eh; - struct ip *ip; - struct udphdr *udp; - - eh = (struct ether_header *)packet; - ip = (struct ip *)(packet+ETHER_HDR_LEN); - udp = (struct udphdr *)(packet+ETHER_HDR_LEN+sizeof(struct ip)); - - if(len < ETHER_HDR_LEN+DHCP_FIXED_LEN) { - logd(LOG_ERR, "length too little -- packet discarded"); - return 0; - } - if(ntohs(eh->ether_type) != ETHERTYPE_IP) { - logd(LOG_ERR, "wrong ether type -- packet discarded"); - return 0; - } - if(udp->uh_ulen < DHCP_FIXED_NON_UDP+DHCP_COOKIE_LEN+1) { - logd(LOG_ERR, "not enough DHCP data -- packet ignore"); - return 0; - } - - return 1; + struct ether_header *eh; + struct ip *ip; + struct udphdr *udp; + + eh = (struct ether_header *)packet; + ip = (struct ip *)(packet + ETHER_HDR_LEN); + udp = (struct udphdr *)(packet + ETHER_HDR_LEN + sizeof(struct ip)); + + if (len < ETHER_HDR_LEN + DHCP_FIXED_LEN) { + logd(LOG_ERR, "length too little -- packet discarded"); + return 0; + } + if (ntohs(eh->ether_type) != ETHERTYPE_IP) { + logd(LOG_ERR, "wrong ether type -- packet discarded"); + return 0; + } + if (udp->uh_ulen < DHCP_FIXED_NON_UDP + DHCP_COOKIE_LEN + 1) { + logd(LOG_ERR, "not enough DHCP data -- packet ignore"); + return 0; + } + return 1; } -/* - * Listen an interface for a DHCP packet (from client) - * and store it in a queue - */ +/* Listen an interface for a DHCP packet (from client) and store it in a + * queue */ void * listener(void *param) { - int i, n, ignore=0, drop; - size_t len; - struct interface *intf = param; - struct pcap_pkthdr *header; - const u_char *packet; - uint8_t *p, *p1; - struct queue *q; - struct timeval curr_pkt; - - while(1) { - if((n=pcap_next_ex(intf->cap, &header, &packet)) > 0) { - /* Drop a packet we got too quickly if we have a RPS limit */ - if(rps_limit) { - gettimeofday(&curr_pkt, NULL); - drop = 0; - pthread_mutex_lock(&last_pkt_lock); - if(DeltaUSec(curr_pkt, last_pkt) < 1000000/rps_limit) - drop = 1; - memcpy(&last_pkt, &curr_pkt, sizeof(struct timeval)); - pthread_mutex_unlock(&last_pkt_lock); - if(drop) - continue; - } - - /* Discard BOOTREPLY from client */ - if(((struct dhcp_packet*)(packet+ETHER_HDR_LEN+DHCP_UDP_OVERHEAD))->op == BOOTREPLY) - continue; - - if(!sanity_check((char*)packet, header->caplen)) - continue; - - len = header->caplen; - p = malloc(len); - if(p == NULL) { - logd(LOG_ERR, "malloc error"); - continue; - } - memcpy(p, packet, len); - - /* If a plugin returns 0, ignore the packet */ - for(i=0; iclient_request) - if(plugins[i]->client_request(intf, &p, &len) == 0) { - logd(LOG_WARNING, "The packet rejected by %s plugin", plugins[i]->name); - ignore = 1; - break; - } - } - if(ignore) { - free(p); - continue; - } - - /* We need no headers anymore, store the packet without them */ - p1 = malloc(len-(ETHER_HDR_LEN+DHCP_UDP_OVERHEAD)); - if(p1 == NULL) { - logd(LOG_ERR, "malloc error"); - free(p); - continue; - } - len-=ETHER_HDR_LEN+DHCP_UDP_OVERHEAD; - memcpy(p1, p+ETHER_HDR_LEN+DHCP_UDP_OVERHEAD, len); - /* We'll free *p after saving ip_dist */ - - q = malloc(sizeof(struct queue)); - if(p1 == NULL) { - logd(LOG_ERR, "malloc error"); - free(p); - free(p1); - continue; - } - q->packet = p1; - q->len = len; - q->if_idx = intf->idx; - q->ip_dst = ((struct ip*)(p+ETHER_HDR_LEN))->ip_dst.s_addr; - /* We don't need *p anymore */ - free(p); - - pthread_mutex_lock(&queue_lock); - STAILQ_INSERT_TAIL(&q_head, q, entries); - queue_size++; - pthread_mutex_unlock(&queue_lock); - } else { - /* Sleep if an error. It prevent us from 100% CPU load if there is an interface problem. */ - usleep(1000); + int i, n, ignore = 0, packet_count = 0; + size_t len; + struct interface *intf = param; + struct pcap_pkthdr *header; + const u_char *packet; + uint8_t *p, *p1; + struct queue *q; + struct timespec tv, last_count_reset_tv = {0, 0}; + + while (1) { + if ((n = pcap_next_ex(intf->cap, &header, &packet)) > 0) { + /* Drop a packet we got too quickly if we have a RPS + * limit */ + if (rps_limit && packet_count++ > rps_limit) { + clock_gettime(CLOCK_MONOTONIC_FAST, &tv); + if (DeltaUSec(tv, last_count_reset_tv) < 1000000) { + logd(LOG_WARNING, "The packet droped due to RPS limit"); + continue; + } else { + memcpy(&last_count_reset_tv, &tv, sizeof(struct timeval)); + packet_count = 0; + } + } + /* Discard BOOTREPLY from client */ + if (((struct dhcp_packet *)(packet + ETHER_HDR_LEN + DHCP_UDP_OVERHEAD))->op == BOOTREPLY) + continue; + + if (!sanity_check((char *)packet, header->caplen)) + continue; + + len = header->caplen; + p = malloc(len); + if (p == NULL) { + logd(LOG_ERR, "malloc error"); + continue; + } + memcpy(p, packet, len); + + /* If a plugin returns 0, ignore the packet */ + for (i = 0; i < plugins_number; i++) { + if (plugins[i]->client_request) + if (plugins[i]->client_request(intf, &p, &len) == 0) { + logd(LOG_WARNING, "The packet rejected by %s plugin", plugins[i]->name); + ignore = 1; + break; + } + } + if (ignore) { + free(p); + continue; + } + /* We need no headers anymore, store the packet + * without them */ + p1 = malloc(len - (ETHER_HDR_LEN + DHCP_UDP_OVERHEAD)); + if (p1 == NULL) { + logd(LOG_ERR, "malloc error"); + free(p); + continue; + } + len -= ETHER_HDR_LEN + DHCP_UDP_OVERHEAD; + memcpy(p1, p + ETHER_HDR_LEN + DHCP_UDP_OVERHEAD, len); + /* We'll free *p after saving ip_dist */ + + q = malloc(sizeof(struct queue)); + if (p1 == NULL) { + logd(LOG_ERR, "malloc error"); + free(p); + free(p1); + continue; + } + q->packet = p1; + q->len = len; + q->if_idx = intf->idx; + q->ip_dst = ((struct ip *)(p + ETHER_HDR_LEN))->ip_dst.s_addr; + /* We don't need *p anymore */ + free(p); + + pthread_mutex_lock(&queue_lock); + STAILQ_INSERT_TAIL(&q_head, q, entries); + queue_size++; + pthread_mutex_unlock(&queue_lock); + } else { + /* Sleep if an error. It prevent us from 100% CPU + * load if there is an interface problem. */ + usleep(1000); + } } - } } -/* - * Only one packet from server is processed at once - * +/* Only one packet from server is processed at once + * */ void process_server_answer() { - struct sockaddr_in from_addr; - struct dhcp_packet *dhcp=NULL; - struct ether_header *eh; - struct ip *ip; - struct udphdr *udp; - struct timeval timeout; - uint8_t *buf=NULL, *packet=NULL; - char pbuf[11+16+19]; - socklen_t from_len=sizeof(from_addr); - int i, j, fdmax=0, ignore, if_idx; - size_t len, psize=0; - fd_set fds; - - FD_ZERO(&fds); - for(i = 0; i < if_num; i++) { - FD_SET(ifs[i]->fd, &fds); - if(fdmax < ifs[i]->fd) - fdmax = ifs[i]->fd; - } - - timeout.tv_sec = 0; - timeout.tv_usec = 10; - if(select(fdmax+1, &fds, NULL, NULL, &timeout)) { - for(i = 0; i < if_num; i++) - if(FD_ISSET(ifs[i]->fd, &fds)) { - bzero(&from_addr, sizeof(from_addr)); - /*from_addr.sin_family=AF_INET; - from_addr.sin_port = bootps_port;*/ - from_len=sizeof(from_addr); - - buf = malloc(max_packet_size); - if(buf == NULL) { - logd(LOG_ERR, "malloc error"); - return; - } - psize = recvfrom(ifs[i]->fd, buf, max_packet_size, 0, - (struct sockaddr*)&from_addr, &from_len); - /* XXX a sanity check? */ - /* If a plugin returns 0, stop processing and do not send the packet */ - ignore = 0; - for(j=0; jserver_answer) - if(plugins[j]->server_answer(&from_addr, &buf, &psize) == 0) { - logd(LOG_WARNING, "The packet rejected by %s plugin", - plugins[j]->name); - ignore = 1; - break; + struct sockaddr_in from_addr; + struct dhcp_packet *dhcp = NULL; + struct ether_header *eh; + struct ip *ip; + struct udphdr *udp; + struct timeval timeout; + uint8_t *buf = NULL, *packet = NULL; + char pbuf[11 + 16 + 19]; + socklen_t from_len = sizeof(from_addr); + int i, j, fdmax = 0, ignore, if_idx; + size_t len, psize = 0; + fd_set fds; + + FD_ZERO(&fds); + for (i = 0; i < if_num; i++) { + FD_SET(ifs[i]->fd, &fds); + if (fdmax < ifs[i]->fd) + fdmax = ifs[i]->fd; + } + + timeout.tv_sec = 0; + timeout.tv_usec = 10; + if (select(fdmax + 1, &fds, NULL, NULL, &timeout)) { + for (i = 0; i < if_num; i++) + if (FD_ISSET(ifs[i]->fd, &fds)) { + bzero(&from_addr, sizeof(from_addr)); + /* from_addr.sin_family=AF_INET; + * from_addr.sin_port = bootps_port; */ + from_len = sizeof(from_addr); + + buf = malloc(max_packet_size); + if (buf == NULL) { + logd(LOG_ERR, "malloc error"); + return; + } + psize = recvfrom(ifs[i]->fd, buf, max_packet_size, 0, + (struct sockaddr *)&from_addr, &from_len); + /* XXX a sanity check? */ + /* If a plugin returns 0, stop processing and + * do not send the packet */ + ignore = 0; + for (j = 0; j < plugins_number; j++) { + if (plugins[j]->server_answer) + if (plugins[j]->server_answer(&from_addr, &buf, &psize) == 0) { + logd(LOG_WARNING, "The packet rejected by %s plugin", + plugins[j]->name); + ignore = 1; + break; + } + } + + if (ignore) { + free(buf); + return; + } + /* Only one packet! */ + break; } - } + } else { + /* No packets from servers */ + return; + } - if(ignore) { - free(buf); - return; - } - /* Only one packet! */ - break; - } - } else { - /* No packets from servers */ - return; - } - - dhcp = (struct dhcp_packet *)buf; - /* Generate a new packet to send to a client */ - packet = malloc(ETHER_HDR_LEN+DHCP_UDP_OVERHEAD+psize); - if(packet == NULL) { - logd(LOG_ERR, "malloc error"); - free(buf); - return; - } - bzero(packet, ETHER_HDR_LEN+DHCP_UDP_OVERHEAD+psize); - eh = (struct ether_header *)packet; - ip = (struct ip *)(packet+ETHER_HDR_LEN); - udp = (struct udphdr *)(packet+ETHER_HDR_LEN+sizeof(struct ip)); - - if_idx = find_interface(*((ip_addr_t*)&dhcp->giaddr)); - if(if_idx == if_num) { - logd(LOG_ERR, "Destination interface not found for: %s", - print_ip(*((ip_addr_t*)&dhcp->giaddr), pbuf)); + dhcp = (struct dhcp_packet *)buf; + /* Generate a new packet to send to a client */ + packet = malloc(ETHER_HDR_LEN + DHCP_UDP_OVERHEAD + psize); + if (packet == NULL) { + logd(LOG_ERR, "malloc error"); + free(buf); + return; + } + bzero(packet, ETHER_HDR_LEN + DHCP_UDP_OVERHEAD + psize); + eh = (struct ether_header *)packet; + ip = (struct ip *)(packet + ETHER_HDR_LEN); + udp = (struct udphdr *)(packet + ETHER_HDR_LEN + sizeof(struct ip)); + + if_idx = find_interface(*((ip_addr_t *)&dhcp->giaddr)); + if (if_idx == if_num) { + logd(LOG_ERR, "Destination interface not found for: %s", + print_ip(*((ip_addr_t *)&dhcp->giaddr), pbuf)); + free(buf); + return; + } + memcpy(eh->ether_shost, ifs[if_idx]->mac, ETHER_ADDR_LEN); + eh->ether_type = htons(ETHERTYPE_IP); + + ip->ip_v = IPVERSION; + ip->ip_hl = 5; /* IP header length is 5 word (no options) */ + ip->ip_tos = IPTOS_LOWDELAY; + ip->ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + psize); + ip->ip_id = 0; + ip->ip_off = 0; + ip->ip_ttl = 16; + ip->ip_p = IPPROTO_UDP; + ip->ip_sum = 0; + memcpy(&ip->ip_src, &ifs[if_idx]->ip, sizeof(ip_addr_t)); + /* Broadcast flag */ + if (dhcp->op == BOOTREPLY && dhcp->flags & 0x80) { + ip->ip_dst.s_addr = INADDR_BROADCAST; + memset(eh->ether_dhost, 0xff, ETHER_ADDR_LEN); + } else { + memcpy(&ip->ip_dst, &dhcp->yiaddr, sizeof(ip_addr_t)); + memcpy(eh->ether_dhost, dhcp->chaddr, ETHER_ADDR_LEN); + } + + udp->uh_sport = bootps_port; + udp->uh_dport = bootpc_port; + udp->uh_ulen = htons(sizeof(struct udphdr) + psize); + udp->uh_sum = 0; /* UDP checksum is optional. we don't care + * it. */ + + memcpy(packet + ETHER_HDR_LEN + DHCP_UDP_OVERHEAD, buf, psize); + ip->ip_sum = htons(ip_checksum((const char *)ip, sizeof(struct ip))); + + len = ETHER_HDR_LEN + DHCP_UDP_OVERHEAD + psize; + ignore = 0; + for (j = 0; j < plugins_number; j++) { + if (plugins[j]->send_to_client) + if (plugins[j]->send_to_client(&from_addr, ifs[if_idx], + &packet, &len) == 0) { + logd(LOG_WARNING, "The packet rejected by %s plugin", plugins[j]->name); + ignore = 1; + break; + } + } + + if (!ignore) + write(ifs[if_idx]->bpf, packet, len); + + free(packet); free(buf); - return; - } - memcpy(eh->ether_shost, ifs[if_idx]->mac, ETHER_ADDR_LEN); - eh->ether_type = htons(ETHERTYPE_IP); - - ip->ip_v = IPVERSION; - ip->ip_hl = 5; /* IP header length is 5 word (no options) */ - ip->ip_tos = IPTOS_LOWDELAY; - ip->ip_len = htons(sizeof(struct ip)+sizeof(struct udphdr)+psize); - ip->ip_id = 0; - ip->ip_off = 0; - ip->ip_ttl = 16; - ip->ip_p = IPPROTO_UDP; - ip->ip_sum = 0; - memcpy(&ip->ip_src, &ifs[if_idx]->ip, sizeof(ip_addr_t)); - /* Broadcast flag */ - if(dhcp->op == BOOTREPLY && dhcp->flags & 0x80) { - ip->ip_dst.s_addr = INADDR_BROADCAST; - memset(eh->ether_dhost, 0xff, ETHER_ADDR_LEN); - } else { - memcpy(&ip->ip_dst, &dhcp->yiaddr, sizeof(ip_addr_t)); - memcpy(eh->ether_dhost, dhcp->chaddr, ETHER_ADDR_LEN); - } - - udp->uh_sport = bootps_port; - udp->uh_dport = bootpc_port; - udp->uh_ulen = htons(sizeof(struct udphdr)+psize); - udp->uh_sum = 0; /* UDP checksum is optional. we don't care it. */ - - memcpy(packet+ETHER_HDR_LEN+DHCP_UDP_OVERHEAD, buf, psize); - ip->ip_sum = htons(ip_checksum((const char*)ip, sizeof(struct ip))); - - len = ETHER_HDR_LEN+DHCP_UDP_OVERHEAD+psize; - ignore = 0; - for(j=0; jsend_to_client) - if(plugins[j]->send_to_client(&from_addr, ifs[if_idx], - &packet, &len) == 0) { - logd(LOG_WARNING, "The packet rejected by %s plugin", plugins[j]->name); - ignore = 1; - break; - } - } - - if(!ignore) - write(ifs[if_idx]->bpf, packet, len); - - free(packet); - free(buf); } -/* - * Get one packet from queue and process it - * (send to server(s)) - */ +/* Get one packet from queue and process it (send to server(s)) */ void process_queue() { - int i, j, ignore, sent=0; - struct queue *q; - struct dhcp_packet *dhcp; - - pthread_mutex_lock(&queue_lock); - q = STAILQ_FIRST(&q_head); - STAILQ_REMOVE_HEAD(&q_head, entries); - queue_size--; - pthread_mutex_unlock(&queue_lock); - - dhcp = (struct dhcp_packet *)q->packet; - - /* Check the packet pass too many hops */ - if(dhcp->hops > max_hops) { - free(q->packet); - free(q); - return; - } - dhcp->hops++; - if(dhcp->giaddr.s_addr == 0) - memcpy(&dhcp->giaddr, &ifs[q->if_idx]->ip, sizeof(ip_addr_t)); - for(i=0; i < ifs[q->if_idx]->srv_num; i++) { - ignore = 0; - for(j=0; jsend_to_server) - if(plugins[j]->send_to_server(&(servers[ifs[q->if_idx]->srvrs[i]]->sockaddr), - &q->packet, &q->len) == 0) { - logd(LOG_WARNING, "The packet rejected by %s plugin", - plugins[j]->name); - ignore = 1; - break; - } + int i, j, ignore, sent = 0; + struct queue *q; + struct dhcp_packet *dhcp; + + pthread_mutex_lock(&queue_lock); + q = STAILQ_FIRST(&q_head); + STAILQ_REMOVE_HEAD(&q_head, entries); + queue_size--; + pthread_mutex_unlock(&queue_lock); + + dhcp = (struct dhcp_packet *)q->packet; + + /* Check the packet pass too many hops */ + if (dhcp->hops > max_hops) { + free(q->packet); + free(q); + return; } + dhcp->hops++; + if (dhcp->giaddr.s_addr == 0) + memcpy(&dhcp->giaddr, &ifs[q->if_idx]->ip, sizeof(ip_addr_t)); + for (i = 0; i < ifs[q->if_idx]->srv_num; i++) { + ignore = 0; + for (j = 0; j < plugins_number; j++) { + if (plugins[j]->send_to_server) + if (plugins[j]->send_to_server(&(servers[ifs[q->if_idx]->srvrs[i]]->sockaddr), + &q->packet, &q->len) == 0) { + logd(LOG_WARNING, "The packet rejected by %s plugin", + plugins[j]->name); + ignore = 1; + break; + } + } - if(!ignore) { - sendto(ifs[q->if_idx]->fd, q->packet, - q->len, 0, - (struct sockaddr *)&servers[ifs[q->if_idx]->srvrs[i]]->sockaddr, - sizeof(struct sockaddr_in)); - sent++; + if (!ignore) { + sendto(ifs[q->if_idx]->fd, q->packet, + q->len, 0, + (struct sockaddr *)&servers[ifs[q->if_idx]->srvrs[i]]->sockaddr, + sizeof(struct sockaddr_in)); + sent++; + } } - } - free(q->packet); - free(q); + free(q->packet); + free(q); } -/* - * Parse a servers part of config - */ +/* Parse a servers part of config */ void -parse_servers_line(char *buf) { - char *p, *n; - int inum; - - p = buf; - strsep(&p, " \t"); - if(!open_server(buf)) { - logd(LOG_WARNING, "Can't open server %s. Ignored.", buf); - return; - } - inum = 0; - while((n = strsep(&p, " \t")) != NULL) { - if(*n != '\0') { - if(open_interface(n)) - inum++; - else { - logd(LOG_WARNING, "Interface %s does not exist. Ignored.", n); - } +parse_servers_line(char *buf) +{ + char *p, *n; + int inum; + + p = buf; + strsep(&p, " \t"); + if (!open_server(buf)) { + logd(LOG_WARNING, "Can't open server %s. Ignored.", buf); + return; + } + inum = 0; + while ((n = strsep(&p, " \t")) != NULL) { + if (*n != '\0') { + if (open_interface(n)) + inum++; + else { + logd(LOG_WARNING, "Interface %s does not exist. Ignored.", n); + } + } + } + /* We found no interfaces for listening on this computer */ + if (inum == 0) { + srv_num--; + free(servers[srv_num]); } - } - /* We found no interfaces for listening on this computer */ - if(inum == 0) { - srv_num--; - free(servers[srv_num]); - } } -/* - * Read and parse a configuration file - */ +/* Read and parse a configuration file */ void read_config(const char *filename) { - char buf[5000], plugin_name[50], plugin_path[100]; - char plugin_data_name[100]; - FILE *f, *fs; - char *p; - int line=0; - void *handle; - enum sections { Servers, Options, Plugin } section = Servers; - struct plugins_data *plugins_data; - struct plugin_options *popt, *last_popt=NULL; - - if((f = fopen(filename, "r")) == NULL) - errx(1, "Can't open: %s", filename); - while(fgets(buf, sizeof(buf), f) != NULL) { - line++; - /* Ignore empty lines and comments */ - if(buf[0] == '\n' || buf[0] == '#') - continue; - - /* strip \n */ - if((p = strchr(buf, '\n')) != NULL) - *p = '\0'; - - /* A new section starts */ - if(buf[0] == '[') { - p = strchr(buf, ']'); - if(p == NULL || *(p+1) != '\0') - errx(1, "Config file syntax error. Line: %d", line); - *p = '\0'; - if(strcasecmp(buf+1, "servers") == 0) { - section = Servers; - continue; - } - if(strcasecmp(buf+1, "options") == 0) { - section = Options; - continue; - } - if((p = strcasestr(buf, "-plugin")) != NULL) { - if(plugins_number > MAX_PLUGINS-1) - errx(1, "Too many plugins. Line: %d", line); - - section = Plugin; - *p = '\0'; - strlcpy(plugin_name, buf+1, sizeof(plugin_name)); - - strlcpy(plugin_data_name, plugin_name, sizeof(plugin_data_name)); - strlcat(plugin_data_name, "_plugin", sizeof(plugin_data_name)); - - strlcpy(plugin_path, plugin_base, sizeof(plugin_path)); - strlcat(plugin_path, "dhcprelya_", sizeof(plugin_path)); - strlcat(plugin_path, plugin_name, sizeof(plugin_path)); - strlcat(plugin_path, "_plugin.so", sizeof(plugin_path)); - handle = dlopen(plugin_path, RTLD_LAZY); - if(handle == NULL) { - printf("dlerror(): %s\n", dlerror()); - errx(1, "Can't open plugin: %s", plugin_path); + char buf[5000], plugin_name[50], plugin_path[100]; + char plugin_data_name[100]; + FILE *f, *fs; + char *p; + int line = 0; + void *handle; + enum sections { + Servers, Options, Plugin + } section = Servers; + struct plugins_data *plugins_data; + struct plugin_options *popt, *last_popt = NULL; + + if ((f = fopen(filename, "r")) == NULL) + errx(1, "Can't open: %s", filename); + while (fgets(buf, sizeof(buf), f) != NULL) { + line++; + /* Ignore empty lines and comments */ + if (buf[0] == '\n' || buf[0] == '#') + continue; + + /* strip \n */ + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; + + /* A new section starts */ + if (buf[0] == '[') { + p = strchr(buf, ']'); + if (p == NULL || *(p + 1) != '\0') + errx(1, "Config file syntax error. Line: %d", line); + *p = '\0'; + if (strcasecmp(buf + 1, "servers") == 0) { + section = Servers; + continue; + } + if (strcasecmp(buf + 1, "options") == 0) { + section = Options; + continue; + } + if ((p = strcasestr(buf, "-plugin")) != NULL) { + if (plugins_number > MAX_PLUGINS - 1) + errx(1, "Too many plugins. Line: %d", line); + + section = Plugin; + *p = '\0'; + strlcpy(plugin_name, buf + 1, sizeof(plugin_name)); + + strlcpy(plugin_data_name, plugin_name, sizeof(plugin_data_name)); + strlcat(plugin_data_name, "_plugin", sizeof(plugin_data_name)); + + strlcpy(plugin_path, plugin_base, sizeof(plugin_path)); + strlcat(plugin_path, "dhcprelya_", sizeof(plugin_path)); + strlcat(plugin_path, plugin_name, sizeof(plugin_path)); + strlcat(plugin_path, "_plugin.so", sizeof(plugin_path)); + handle = dlopen(plugin_path, RTLD_LAZY); + if (handle == NULL) { + printf("dlerror(): %s\n", dlerror()); + errx(1, "Can't open plugin: %s", plugin_path); + } + plugins_data = dlsym(handle, plugin_data_name); + if (plugins_data == NULL) + errx(1, "Can't load symbol %s", plugin_data_name); + plugins[plugins_number] = malloc(sizeof(struct plugin_data)); + if (plugins[plugins_number] == NULL) + process_error(EX_MEM, "malloc"); + + memcpy(plugins[plugins_number], plugins_data, sizeof(struct plugin_data)); + + /* head for options list for this plugin */ + options_heads[plugins_number] = malloc(sizeof(plugin_options_head_t)); + if (options_heads[plugins_number] == NULL) + process_error(EX_MEM, "malloc"); + SLIST_INIT(options_heads[plugins_number]); + + plugins_number++; + + logd(LOG_DEBUG, "Plugin #%d (%s) loaded", plugins_number, plugin_name); + continue; + } + errx(1, "Section name error. Line: %d", line); + } + if (section == Servers) { + if ((p = strchr(buf, '=')) == NULL) + parse_servers_line(buf); + else { + *p = '\0'; + p++; + if (strcasecmp(buf, "file") != 0) + errx(1, "Unknown option in Server section. Line: %d", line); + if ((fs = fopen(p, "r")) == NULL) + errx(1, "Can't open servers config file: %s", p); + while (fgets(buf, sizeof(buf), fs) != NULL) { + /* Ignore empty lines and comments */ + if (buf[0] == '\n' || buf[0] == '#') + continue; + + /* strip \n */ + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; + + parse_servers_line(buf); + } + fclose(fs); + } } + if (section == Options) { + p = strchr(buf, '='); + if (p == NULL) + errx(1, "Option error. Line: %d", line); + *p = '\0'; + p++; + + if (strcasecmp(buf, "max_packet_size") == 0) { + max_packet_size = strtol(p, NULL, 10); + if (max_packet_size < 300 || max_packet_size > DHCP_MTU_MAX) + errx(1, "Wrong packet size. Line: %d", line); + logd(LOG_DEBUG, "Option max_packet_size set to: %d", max_packet_size); + continue; + } + if (strcasecmp(buf, "max_hops") == 0) { + max_hops = strtol(p, NULL, 10); + if (max_hops < 1 || max_hops > 16) + errx(1, "Wrong hops number. Line: %d", line); + logd(LOG_DEBUG, "Option max_hops set to: %d", max_hops); + continue; + } + if (strcasecmp(buf, "rps_limit") == 0) { + errno = 0; + rps_limit = strtol(p, NULL, 10); + if (errno != 0) + errx(1, "rps_limit number error"); + logd(LOG_DEBUG, "Option rps_limit set to: %d", rps_limit); + continue; + } + if (strcasecmp(buf, "plugin_path") == 0) { + strlcpy(plugin_base, p, sizeof(plugin_base)); + if (plugin_base[strlen(plugin_base) - 1] != '/') + strlcat(plugin_base, "/", sizeof(plugin_base)); + logd(LOG_DEBUG, "Option plugin_base set to: %s", plugin_base); + continue; + } + errx(1, "Unknown option. Line: %d", line); + } + if (section == Plugin) { + popt = malloc(sizeof(struct plugin_options)); + if (popt == NULL) + process_error(EX_MEM, "malloc"); + popt->option_line = malloc(strlen(buf) + 1); + if (popt->option_line == NULL) + process_error(EX_MEM, "malloc"); + strcpy(popt->option_line, buf); + if (SLIST_EMPTY(options_heads[plugins_number - 1])) { + SLIST_INSERT_HEAD(options_heads[plugins_number - 1], popt, next); + last_popt = popt; + } else { + SLIST_INSERT_AFTER(last_popt, popt, next); + last_popt = popt; + } + } + } + fclose(f); + if (if_num == 0) + errx(1, "No interfaces found to listen. Exiting."); +} - plugins_data = dlsym(handle, plugin_data_name); - if(plugins_data == NULL) - errx(1, "Can't load symbol %s", plugin_data_name); - plugins[plugins_number] = malloc(sizeof(struct plugin_data)); - if(plugins[plugins_number] == NULL) - process_error(EX_MEM, "malloc"); +int +main(int argc, char *argv[]) +{ + int c, i, j, configured = 0; + pid_t opid; + char prgname[80], filename[256], *p; + struct servent *servent; + pthread_t tid; + + /* Default plugin_base */ + strlcpy(plugin_base, PLUGIN_PATH, sizeof(plugin_base)); + + if ((servent = getservbyname("bootps", 0)) == NULL) + errx(EX_UNAVAILABLE, "getservbyname(bootps)"); + bootps_port = servent->s_port; + if ((servent = getservbyname("bootpc", 0)) == NULL) + errx(EX_UNAVAILABLE, "getservbyname(bootpc)"); + bootpc_port = servent->s_port; + + openlog("dhcprelya", LOG_NDELAY | LOG_PID, LOG_DAEMON); + + strlcpy(prgname, argv[0], sizeof(prgname)); + filename[0] = '\0'; + while ((c = getopt(argc, argv, "A:c:df:hi:p:")) != -1) { + switch (c) { + case 'A': + if (configured == 2) + errx(1, "Either config file or command line options allowed. Not both."); + max_packet_size = strtol(optarg, NULL, 10); + if (max_packet_size < 300 || max_packet_size > DHCP_MTU_MAX) + errx(1, "Wrong packet size"); + break; + case 'c': + if (configured == 2) + errx(1, "Either config file or command line options allowed. Not both."); + max_hops = strtol(optarg, NULL, 10); + if (max_hops < 1 || max_hops > 16) + errx(1, "Wrong hops number"); + break; + case 'd': + debug++; + break; + case 'f': + if (configured == 1) + errx(1, "Either config file or command line options allowed. Not both."); + if (configured == 2) + errx(1, "only one config file allowed"); + configured = 2; + read_config(optarg); + break; + case 'i': + if (configured == 2) + errx(1, "Either config file or command line options allowed. Not both."); + configured = 1; + if (!open_interface(optarg)) + logd(LOG_DEBUG, "Interface %s does not exist. Ignored.", optarg); + break; + case 'p': + strlcpy(filename, optarg, sizeof(filename)); + break; + case 'h': + default: + usage(prgname); + } + } - memcpy(plugins[plugins_number], plugins_data, sizeof(struct plugin_data)); + argc -= optind; + argv += optind; - /* head for options list for this plugin */ - options_heads[plugins_number] = malloc(sizeof(plugin_options_head_t)); - if(options_heads[plugins_number] == NULL) - process_error(EX_MEM, "malloc"); - SLIST_INIT(options_heads[plugins_number]); + if (optind == 0) + argc--; - plugins_number++; + if ((configured == 1 && argc < 1) || (configured == 2 && argc >= 1)) + usage(prgname); - logd(LOG_DEBUG, "Plugin #%d (%s) loaded", plugins_number, plugin_name); - continue; - } - errx(1, "Section name error. Line: %d", line); + /* Initialize polugins */ + for (i = 0; i < plugins_number; i++) { + if (plugins[i]->init) + if ((plugins[i]->init) (options_heads[i]) == 0) + errx(1, "Can't initialize a plugin %s\n", plugins[i]->name); } - if(section == Servers) { - if((p = strchr(buf, '=')) == NULL) - parse_servers_line(buf); - else { - *p = '\0'; p++; - if(strcasecmp(buf, "file") != 0) - errx(1, "Unknown option in Server section. Line: %d", line); - if((fs = fopen(p, "r")) == NULL) - errx(1, "Can't open servers config file: %s", p); - while(fgets(buf, sizeof(buf), fs) != NULL) { - /* Ignore empty lines and comments */ - if(buf[0] == '\n' || buf[0] == '#') - continue; - - /* strip \n */ - if((p = strchr(buf, '\n')) != NULL) - *p = '\0'; - parse_servers_line(buf); + for (i = 0; i < argc; i++) { + open_server(argv[i]); + for (j = 0; j < if_num; j++) { + if (i > ifs[j]->srv_num - 1) { + ifs[j]->srv_num++; + ifs[j]->srvrs = realloc(ifs[j]->srvrs, ifs[j]->srv_num * sizeof(int)); + } + ifs[j]->srvrs[ifs[i]->srv_num - 1] = i; } - fclose(fs); - } } - if(section == Options) { - p = strchr(buf, '='); - if(p == NULL) - errx(1, "Option error. Line: %d", line); - *p = '\0'; - p++; - - if(strcasecmp(buf, "max_packet_size") == 0) { - max_packet_size = strtol(p, NULL, 10); - if(max_packet_size < 300 || max_packet_size > DHCP_MTU_MAX) - errx(1, "Wrong packet size. Line: %d", line); - logd(LOG_DEBUG, "Option max_packet_size set to: %d", max_packet_size); - continue; - } - if(strcasecmp(buf, "max_hops") == 0) { - max_hops = strtol(p, NULL, 10); - if(max_hops < 1 || max_hops > 16) - errx(1, "Wrong hops number. Line: %d", line); - logd(LOG_DEBUG, "Option max_hops set to: %d", max_hops); - continue; - } - if(strcasecmp(buf, "rps_limit") == 0) { - errno = 0; - rps_limit = strtol(p, NULL, 10); - if(errno != 0) - errx(1, "rps_limit number error"); - logd(LOG_DEBUG, "Option rps_limit set to: %d", rps_limit); - continue; - } - if(strcasecmp(buf, "plugin_path") == 0) { - strlcpy(plugin_base, p, sizeof(plugin_base)); - if(plugin_base[strlen(plugin_base)-1] != '/') - strlcat(plugin_base, "/", sizeof(plugin_base)); - logd(LOG_DEBUG, "Option plugin_base set to: %s", plugin_base); - continue; - } - errx(1, "Unknown option. Line: %d", line); + + if (if_num == 0) + errx(1, "No interfaces found to listen. Exiting."); + + logd(LOG_WARNING, "Total interfaces: %d", if_num); + + /* Make a PID filename */ + if (filename[0] == '\0') { + strlcpy(filename, "/var/run/", sizeof(filename)); + p = strrchr(prgname, '/'); + if (p == NULL) + p = prgname; + else + p++; + strlcat(filename, p, sizeof(filename)); + strlcat(filename, ".pid", sizeof(filename)); } - if(section == Plugin) { - popt = malloc(sizeof(struct plugin_options)); - if(popt == NULL) - process_error(EX_MEM, "malloc"); - popt->option_line = malloc(strlen(buf)+1); - if(popt->option_line == NULL) - process_error(EX_MEM, "malloc"); - strcpy(popt->option_line, buf); - if(SLIST_EMPTY(options_heads[plugins_number-1])) { - SLIST_INSERT_HEAD(options_heads[plugins_number-1], popt, next); - last_popt = popt; - } else { - SLIST_INSERT_AFTER(last_popt, popt, next); - last_popt = popt; - } + /* Create a PID file and daemonize if no debug flag */ + if (!debug && (pfh = pidfile_open(filename, 0644, &opid)) == NULL) { + if (errno == EEXIST) + errx(1, "Already run with PID %lu. Exiting.", (unsigned long)opid); + errx(1, "Can't create PID file"); } - } - fclose(f); - if(if_num == 0) - errx(1, "No interfaces found to listen. Exiting."); -} + signal(SIGHUP, SIG_IGN); -int -main(int argc, char *argv[]) -{ - int c, i, j, configured=0; - pid_t opid; - char prgname[80], filename[256], *p; - struct servent *servent; - pthread_t tid; - - /* Default plugin_base */ - strlcpy(plugin_base, PLUGIN_PATH, sizeof(plugin_base)); - - if((servent = getservbyname("bootps", 0)) == NULL) - errx(EX_UNAVAILABLE, "getservbyname(bootps)"); - bootps_port=servent->s_port; - if((servent = getservbyname("bootpc", 0)) == NULL) - errx(EX_UNAVAILABLE, "getservbyname(bootpc)"); - bootpc_port=servent->s_port; - - openlog("dhcprelya", LOG_NDELAY|LOG_PID, LOG_DAEMON); - - strlcpy(prgname, argv[0], sizeof(prgname)); - filename[0] = '\0'; - while((c = getopt(argc, argv, "A:c:df:hi:p:")) != -1) { - switch(c) { - case 'A': - if(configured == 2) - errx(1, "Either config file or command line options allowed. Not both."); - max_packet_size = strtol(optarg, NULL, 10); - if(max_packet_size < 300 || max_packet_size > DHCP_MTU_MAX) - errx(1, "Wrong packet size"); - break; - case 'c': - if(configured == 2) - errx(1, "Either config file or command line options allowed. Not both."); - max_hops = strtol(optarg, NULL, 10); - if(max_hops < 1 || max_hops > 16) - errx(1, "Wrong hops number"); - break; - case 'd': - debug++; - break; - case 'f': - if(configured == 1) - errx(1, "Either config file or command line options allowed. Not both."); - if(configured == 2) - errx(1, "only one config file allowed"); - configured=2; - read_config(optarg); - break; - case 'i': - if(configured == 2) - errx(1, "Either config file or command line options allowed. Not both."); - configured=1; - if(!open_interface(optarg)) - logd(LOG_DEBUG, "Interface %s does not exist. Ignored.", optarg); - break; - case 'p': - strlcpy(filename, optarg, sizeof(filename)); - break; - case 'h': - default: - usage(prgname); + if (!debug) { + if (daemon(0, 0) == -1) + process_error(1, "Can't daemonize. Exiting."); + else + logd(LOG_DEBUG, "Runned as %d", getpid()); } - } + if (pfh) + pidfile_write(pfh); - argc -= optind; - argv += optind; + STAILQ_INIT(&q_head); - if(optind == 0) - argc--; + pthread_mutex_init(&queue_lock, NULL); - if((configured == 1 && argc < 1) || (configured == 2 && argc >=1)) - usage(prgname); + /* Create listeners for every interface */ + for (i = 0; i < if_num; i++) { + pthread_create(&tid, NULL, listener, ifs[i]); + pthread_detach(tid); + } - /* Initialize polugins */ - for(i=0; iinit) - if((plugins[i]->init)(options_heads[i]) == 0) - errx(1, "Can't initialize a plugin %s\n", plugins[i]->name); - } + /* Main loop */ + while (1) { + if (queue_size > 0) + process_queue(); - for(i=0; i ifs[j]->srv_num - 1) { - ifs[j]->srv_num++; - ifs[j]->srvrs = realloc(ifs[j]->srvrs, ifs[j]->srv_num*sizeof(int)); - } + /* Process one packet from server(s) */ + process_server_answer(); + } - ifs[j]->srvrs[ifs[i]->srv_num - 1] = i; + /* Destroy polugins */ + for (i = 0; i < plugins_number; i++) { + if (plugins[i]->destroy) + (plugins[i]->destroy) (); } - } - - if(if_num == 0) - errx(1, "No interfaces found to listen. Exiting."); - - logd(LOG_WARNING, "Total interfaces: %d", if_num); - - /* Make a PID filename */ - if(filename[0] == '\0') { - strlcpy(filename, "/var/run/", sizeof(filename)); - p = strrchr(prgname, '/'); - if(p == NULL) - p = prgname; - else - p++; - strlcat(filename, p, sizeof(filename)); - strlcat(filename, ".pid", sizeof(filename)); - } - - /* Create a PID file and daemonize if no debug flag */ - if(!debug && (pfh = pidfile_open(filename, 0644, &opid)) == NULL) { - if(errno == EEXIST) - errx(1, "Already run with PID %lu. Exiting.", (unsigned long)opid); - errx(1, "Can't create PID file"); - } - - signal(SIGHUP, SIG_IGN); - - if(!debug) { - if(daemon(0,0) == -1) - process_error(1, "Can't daemonize. Exiting."); - else - logd(LOG_DEBUG, "Runned as %d", getpid()); - } - - if(pfh) - pidfile_write(pfh); - - STAILQ_INIT(&q_head); - - pthread_mutex_init(&queue_lock, NULL); - pthread_mutex_init(&last_pkt_lock, NULL); - - /* Create listeners for every interface */ - for(i = 0; i < if_num; i++) { - pthread_create(&tid, NULL, listener, ifs[i]); - pthread_detach(tid); - } - - /* Main loop */ - while(1) { - if(queue_size > 0) - process_queue(); - - /* Process one packet from server(s) */ - process_server_answer(); - } - - /* Destroy polugins */ - for(i=0; idestroy) - (plugins[i]->destroy)(); - } - pthread_mutex_destroy(&queue_lock); - pthread_mutex_destroy(&last_pkt_lock); + pthread_mutex_destroy(&queue_lock); } diff --git a/dhcprelya.conf-example b/dhcprelya.conf-example index a92e373..d502a53 100644 --- a/dhcprelya.conf-example +++ b/dhcprelya.conf-example @@ -16,7 +16,7 @@ dhcpserver2:1067 vlan1 vlan5 # A maximum hop counts after a packet will discarded # 1<=max_hops<16 #max_hops=4 -# Request rate limit (packets in second). 0 - off. +# Per-interface request rate limit (packets in second). 0 - off. #rps_limit=0 # Look for plugins in this directory #plugin_path=/usr/local/lib/ diff --git a/dhcprelya.h b/dhcprelya.h index fe26f08..140704a 100644 --- a/dhcprelya.h +++ b/dhcprelya.h @@ -1,31 +1,28 @@ -/* - * Copyright (c) 2007-2012 Sergey Matveychuk - * Yandex, LLC. All rights reserved. - * +/* Copyright (c) 2007-2012 Sergey Matveychuk Yandex, LLC. All rights + * reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 4. Neither the name + * of the company nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ + * SUCH DAMAGE. */ #ifndef _DHCP_H #define _DHCP_H @@ -43,8 +40,8 @@ #include #include -#define IF_MAX 100 /* Max interfaces supported */ -#define SERVERS_MAX 10 /* Max servers supported */ +#define IF_MAX 100 /* Max interfaces supported */ +#define SERVERS_MAX 10 /* Max servers supported */ /* Error codes */ #define EX_OK 0 @@ -58,12 +55,12 @@ #define ETH_ADDR_LEN 6 #define DHCP_UDP_OVERHEAD (20 + /* IP header */ \ - 8) /* UDP header */ + 8) /* UDP header */ #define DHCP_SNAME_LEN 64 #define DHCP_FILE_LEN 128 #define DHCP_FIXED_NON_UDP 236 #define DHCP_FIXED_LEN (DHCP_FIXED_NON_UDP + DHCP_UDP_OVERHEAD) - /* Everything but options. */ +/* Everything but options. */ #define DHCP_MTU_MAX 1500 #define DHCP_OPTION_LEN (DHCP_MTU_MAX - DHCP_FIXED_LEN) #define DHCP_COOKIE_LEN 4 @@ -73,53 +70,52 @@ #define BOOTREPLY 2 struct dhcp_packet { - uint8_t op; /* 0: Message opcode/type */ - uint8_t htype; /* 1: Hardware addr type (net/if_types.h) */ - uint8_t hlen; /* 2: Hardware addr length */ - uint8_t hops; /* 3: Number of relay agent hops from client */ - uint32_t xid; /* 4: Transaction ID */ - uint16_t secs; /* 8: Seconds since client started looking */ - uint16_t flags; /* 10: Flag bits */ - struct in_addr ciaddr; /* 12: Client IP address (if already in use) */ - struct in_addr yiaddr; /* 16: Client IP address */ - struct in_addr siaddr; /* 20: IP address of next server to talk to */ - struct in_addr giaddr; /* 24: DHCP relay agent IP address */ - unsigned char chaddr[16]; /* 28: Client hardware address */ - char sname[DHCP_SNAME_LEN]; /* 44: Server name */ - char file[DHCP_FILE_LEN]; /* 108: Boot filename */ - unsigned char options[DHCP_OPTION_LEN]; - /* 236: Optional parameters - (actual length dependent on MTU). */ + uint8_t op; /* 0: Message opcode/type */ + uint8_t htype; /* 1: Hardware addr type (net/if_types.h) */ + uint8_t hlen; /* 2: Hardware addr length */ + uint8_t hops; /* 3: Number of relay agent hops from client */ + uint32_t xid; /* 4: Transaction ID */ + uint16_t secs; /* 8: Seconds since client started looking */ + uint16_t flags; /* 10: Flag bits */ + struct in_addr ciaddr; /* 12: Client IP address (if already in use) */ + struct in_addr yiaddr; /* 16: Client IP address */ + struct in_addr siaddr; /* 20: IP address of next server to talk to */ + struct in_addr giaddr; /* 24: DHCP relay agent IP address */ + unsigned char chaddr[16]; /* 28: Client hardware address */ + char sname[DHCP_SNAME_LEN]; /* 44: Server name */ + char file[DHCP_FILE_LEN]; /* 108: Boot filename */ + unsigned char options[DHCP_OPTION_LEN]; + /* 236: Optional parameters (actual length dependent on MTU). */ }; -typedef in_addr_t ip_addr_t; +typedef in_addr_t ip_addr_t; struct interface { - int idx; - int fd; - char name[INTF_NAME_LEN]; - ip_addr_t ip; - ip_addr_t mask; - uint8_t mac[6]; - int bpf; - pcap_t *cap; - int srv_num; - int *srvrs; + int idx; + int fd; + char name[INTF_NAME_LEN]; + ip_addr_t ip; + ip_addr_t mask; + uint8_t mac[6]; + int bpf; + pcap_t *cap; + int srv_num; + int *srvrs; }; struct dhcp_server { - char *name; - struct sockaddr_in sockaddr; + char *name; + struct sockaddr_in sockaddr; }; STAILQ_HEAD(queue_head, queue) q_head; struct queue { - uint8_t *packet; - size_t len; - int if_idx; + uint8_t *packet; + size_t len; + int if_idx; ip_addr_t ip_dst; - STAILQ_ENTRY(queue) entries; + STAILQ_ENTRY(queue) entries; }; /* Global options */ @@ -130,8 +126,8 @@ short ip_checksum(const char *addr, int count); char *print_mac(uint8_t *s, char *buf); char *print_ip(ip_addr_t ip, char *buf); char *print_xid(uint32_t ip, char *buf); -void logd(int log_level, char *fmt, ...); -int get_bool_value(const char *str); +void logd(int log_level, char *fmt,...); +int get_bool_value(const char *str); /* net_utils.c */ int get_mac(char *if_name, char *if_mac); @@ -142,33 +138,32 @@ int get_ip(char *iname, ip_addr_t *ip, ip_addr_t *mask); #define PLUGIN_PATH "/usr/local/lib/" struct plugin_options { - char *option_line; - SLIST_ENTRY(plugin_options) next; + char *option_line; + SLIST_ENTRY(plugin_options) next; }; -typedef SLIST_HEAD(opt_head, plugin_options) plugin_options_head_t; - -/* - * Be aware: - * - * client_request() gets a packet with link-level headers - * send_to_server() gets a stripped packet - * server_answer() gets a stripped packet - * send_to_client() gets a packet with link-level header - */ +typedef +SLIST_HEAD(opt_head, plugin_options) +plugin_options_head_t; + +/* Be aware: + * + * client_request() gets a packet with link-level headers send_to_server() gets + * a stripped packet server_answer() gets a stripped packet send_to_client() + * gets a packet with link-level header */ struct plugin_data { - char *name; - int (*init)(plugin_options_head_t *poptions); - void (*destroy)(); - /* packet buffer could be reallocated in functions bellow */ - int (*client_request)(const struct interface *intf, - uint8_t **packet, size_t *psize); - int (*send_to_server)(const struct sockaddr_in *server, - uint8_t **packet, size_t *psize); - int (*server_answer)(const struct sockaddr_in *server, - uint8_t **packet, size_t *psize); - int (*send_to_client)(const struct sockaddr_in *server, - const struct interface *intf, uint8_t **packet, - size_t *psize); + char *name; + int (*init) (plugin_options_head_t *poptions); + void (*destroy) (); + /* packet buffer could be reallocated in functions bellow */ + int (*client_request) (const struct interface *intf, + uint8_t **packet, size_t *psize); + int (*send_to_server) (const struct sockaddr_in *server, + uint8_t **packet, size_t *psize); + int (*server_answer) (const struct sockaddr_in *server, + uint8_t **packet, size_t *psize); + int (*send_to_client) (const struct sockaddr_in *server, + const struct interface *intf, uint8_t **packet, + size_t *psize); }; #endif diff --git a/ip_checksum.c b/ip_checksum.c index 8e4d2f5..f5aa40d 100644 --- a/ip_checksum.c +++ b/ip_checksum.c @@ -1,67 +1,58 @@ -/* - * - * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, - * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE - * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. - * In no event shall NetworkCS be responsible for any damages, including - * but not limited to consequential damages, arising from or relating to - * any use of the Software or related support. - * +/* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE SOFTWARE OR ANY + * SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. In no event shall + * NetworkCS be responsible for any damages, including but not limited to + * consequential damages, arising from or relating to any use of the Software + * or related support. + * * Copyright 1994-1998 Network Computing Services, Inc. - * - * Copies of this Software may be made, however, the above copyright - * notice must be reproduced on all copies. - */ + * + * Copies of this Software may be made, however, the above copyright notice must + * be reproduced on all copies. */ #include -/* - * User Space Library Functions - * ---------------------------- - * +/* User Space Library Functions ---------------------------- + * * IP checksum computation - * + * */ -/* - * Compute an IP checksum - * +/* Compute an IP checksum + * * This code was taken from RFC 1071. - * - * "The following "C" code algorithm computes the checksum with an inner - * loop that sums 16 bits at a time in a 32-bit accumulator." - * - * Arguments: - * addr pointer to the buffer whose checksum is to be computed - * count number of bytes to include in the checksum - * - * Returns: - * the computed checksum - * + * + * "The following "C" code algorithm computes the checksum with an inner loop + * that sums 16 bits at a time in a 32-bit accumulator." + * + * Arguments: addr pointer to the buffer whose checksum is to be computed count + * number of bytes to include in the checksum + * + * Returns: the computed checksum + * */ short ip_checksum(const char *addr, int count) { - /* Compute Internet Checksum for "count" bytes - * beginning at location "addr". - */ + /* Compute Internet Checksum for "count" bytes beginning at location + * "addr". */ long sum = 0; - while( count > 1 ) { + while (count > 1) { /* This is the inner loop */ - sum += ntohs(* (const unsigned short *)(const void *)addr); + sum += ntohs(*(const unsigned short *)(const void *)addr); addr += sizeof(unsigned short); count -= sizeof(unsigned short); } /* Add left-over byte, if any */ - if( count > 0 ) - sum += * (const unsigned char *) addr; + if (count > 0) + sum += *(const unsigned char *)addr; /* Fold 32-bit sum to 16 bits */ - while (sum>>16) + while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); - return((short)~sum); + return ((short)~sum); } diff --git a/log_plugin.c b/log_plugin.c index 0a1f295..c6f5e2a 100644 --- a/log_plugin.c +++ b/log_plugin.c @@ -1,31 +1,28 @@ -/* - * Copyright (c) 2007-2012 Sergey Matveychuk - * Yandex, LLC. All rights reserved. - * +/* Copyright (c) 2007-2012 Sergey Matveychuk Yandex, LLC. All rights + * reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 4. Neither the name + * of the company nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ + * SUCH DAMAGE. */ #include #include @@ -45,501 +42,516 @@ #define SPERH (3600) #define SPERM (60) -static unsigned detailed=0, print_only_incoming=0; +static unsigned detailed = 0, print_only_incoming = 0; int log_plugin_init(plugin_options_head_t *options_head) { - struct plugin_options *opts, *opts_tmp; - char *p; - - SLIST_FOREACH_SAFE(opts, options_head, next, opts_tmp) { - if((p = strchr(opts->option_line, '=')) == NULL) { - logd(LOG_ERR, "log_plugin: Syntax error at line: %s", opts->option_line); - return 0; - } - *p = '\0'; p++; - if(strcasecmp(opts->option_line, "detailed") == 0) { - if((detailed=get_bool_value(p)) == -1) { - logd(LOG_ERR, "log_plugin: Syntax error at line: %s", opts->option_line); - return 0; - } - if(detailed) - logd(LOG_DEBUG, "log_plugin: Detailed: on"); - } else if(strcasecmp(opts->option_line, "print_only_incoming") == 0) { - if((print_only_incoming=get_bool_value(p)) == -1) { - logd(LOG_ERR, "log_plugin: Syntax error at line: %s", opts->option_line); - return 0; - } - if(print_only_incoming) - logd(LOG_DEBUG, "log_plugin: Print only incoming: on"); - } else { - logd(LOG_ERR, "log_plugin: Unknown option at line: %s", opts->option_line); - return 0; + struct plugin_options *opts, *opts_tmp; + char *p; + + SLIST_FOREACH_SAFE(opts, options_head, next, opts_tmp) { + if ((p = strchr(opts->option_line, '=')) == NULL) { + logd(LOG_ERR, "log_plugin: Syntax error at line: %s", opts->option_line); + return 0; + } + *p = '\0'; + p++; + if (strcasecmp(opts->option_line, "detailed") == 0) { + if ((detailed = get_bool_value(p)) == -1) { + logd(LOG_ERR, "log_plugin: Syntax error at line: %s", opts->option_line); + return 0; + } + if (detailed) + logd(LOG_DEBUG, "log_plugin: Detailed: on"); + } else if (strcasecmp(opts->option_line, "print_only_incoming") == 0) { + if ((print_only_incoming = get_bool_value(p)) == -1) { + logd(LOG_ERR, "log_plugin: Syntax error at line: %s", opts->option_line); + return 0; + } + if (print_only_incoming) + logd(LOG_DEBUG, "log_plugin: Print only incoming: on"); + } else { + logd(LOG_ERR, "log_plugin: Unknown option at line: %s", opts->option_line); + return 0; + } + free(opts->option_line); + SLIST_REMOVE(options_head, opts, plugin_options, next); + free(opts); } - free(opts->option_line); - SLIST_REMOVE(options_head, opts, plugin_options, next); - free(opts); - } - return 1; + return 1; } void log_plugin_get_time(char *buf) { - struct timeval tv; - struct timezone tz; - struct tm tm; - - gettimeofday(&tv, &tz); - localtime_r((const time_t*)&tv.tv_sec, &tm); - sprintf(buf, "%02d:%02d:%02d.%06lu", - tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); + struct timeval tv; + struct timezone tz; + struct tm tm; + + gettimeofday(&tv, &tz); + localtime_r((const time_t *)&tv.tv_sec, &tm); + sprintf(buf, "%02d:%02d:%02d.%06lu", + tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); } -/* - * print the data as a hex-list, with the translation into ascii behind it - */ +/* print the data as a hex-list, with the translation into ascii behind it */ void printHexString(uint8_t *data, int len) { - int i, j, k; - char c; - - for(i = 0; i <= len / 8; i++) { - for(j = 0; j < 8; j++) { - if(i * 8 + j >= len) - break; - printf("%02x", data[i * 8 + j]); + int i, j, k; + char c; + + for (i = 0; i <= len / 8; i++) { + for (j = 0; j < 8; j++) { + if (i * 8 + j >= len) + break; + printf("%02x", data[i * 8 + j]); + } + for (k = j; k < 8; k++) + printf(" "); + printf(" "); + for (j = 0; j < 8; j++) { + c = data[i * 8 + j]; + if (i * 8 + j >= len) + break; + printf("%c", isprint(c) ? c : '.'); + } + if (i * 8 + j < len) + printf("\n\t\t\t\t\t "); } - for(k = j; k < 8; k++) - printf(" "); - printf(" "); - for(j = 0; j < 8; j++) { - c = data[i * 8 + j]; - if (i * 8 + j >= len) - break; - printf("%c", isprint(c) ? c : '.'); - } - if(i * 8 + j < len) - printf("\n\t\t\t\t\t "); - } } -/* - * print the data as a hex-list, without the translation into ascii behind it - */ +/* print the data as a hex-list, without the translation into ascii behind it */ void printHex(uint8_t *data, int len) { - int i, j; - - for(i = 0; i <= len / 8; i++) { - for(j = 0; j < 8; j++) { - if (i * 8 + j >= len) break; - printf("%02x", data[i * 8 + j]); + int i, j; + + for (i = 0; i <= len / 8; i++) { + for (j = 0; j < 8; j++) { + if (i * 8 + j >= len) + break; + printf("%02x", data[i * 8 + j]); + } + if (i * 8 + j < len) + printf("\n\t\t\t\t\t "); } - if(i * 8 + j < len) printf("\n\t\t\t\t\t "); - } } -/* - * print the data as a hex-list seperated by colons - */ +/* print the data as a hex-list seperated by colons */ void printHexColon(uint8_t *data, int len) { - int i; + int i; - for(i = 0; i < len; i++) { - if(i != 0 ) printf(":"); - printf("%02x", data[i]); - } + for (i = 0; i < len; i++) { + if (i != 0) + printf(":"); + printf("%02x", data[i]); + } } void print_word(uint8_t *data) { - printf("%d", (data[0] << 8) + data[1]); + printf("%d", (data[0] << 8) + data[1]); } /* print the data as a 8 and 32 bits time-value */ void print_time(uint8_t *data, int bits) { - int t; - - if(bits == BITS8) - t = data[0]; - else - t = (data[0] << 24) + (data[1] << 16) + (data[2] <<8 ) + data[3]; - - printf("%d (", t); - if(t > SPERW) { printf("%dw", t / (SPERW)); t %= SPERW; } - if(t > SPERD) { printf("%dd", t / (SPERD)); t %= SPERD; } - if(t > SPERH) { printf("%dh", t / (SPERH)); t %= SPERH; } - if(t > SPERM) { printf("%dm", t / (SPERM)); t %= SPERM; } - if(t > 0) printf("%ds", t); - printf(")"); + int t; + + if (bits == BITS8) + t = data[0]; + else + t = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]; + + printf("%d (", t); + if (t > SPERW) { + printf("%dw", t / (SPERW)); + t %= SPERW; + } + if (t > SPERD) { + printf("%dd", t / (SPERD)); + t %= SPERD; + } + if (t > SPERH) { + printf("%dh", t / (SPERH)); + t %= SPERH; + } + if (t > SPERM) { + printf("%dm", t / (SPERM)); + t %= SPERM; + } + if (t > 0) + printf("%ds", t); + printf(")"); } void printReqParmList(uint8_t *data, int len) { - int i; + int i; - for (i = 0; i < len; i++) { - printf("%3d (%s)\n", data[i], dhcp_options[data[i]]); - printf("\t\t\t\t\t "); - } + for (i = 0; i < len; i++) { + printf("%3d (%s)\n", data[i], dhcp_options[data[i]]); + printf("\t\t\t\t\t "); + } } void print_dhcp_packet(struct dhcp_packet *dhcp, int data_len) { - char buf[1024]; - uint8_t *data; - int i, j; - - puts("---------------------------------------------------------------------------"); - printf("op: %d (%s)\n", dhcp->op, - dhcp->op==1?"BOOTREQUEST":(dhcp->op==2?"BOOTREPLY":"illegal")); - printf("htype: %d (%s)\n", dhcp->htype, dhcp->htype==1?"Ethernet":""); - printf("hlen: %d\n", dhcp->hlen); - printf("hops: %d\n", dhcp->hops); - printf("xid: %s\n", print_xid(dhcp->xid, buf)); - printf("secs: %d\n", dhcp->secs); - printf("flags: 0x%X\n", dhcp->flags); - printf("ciaddr: %s\n", print_ip(dhcp->ciaddr.s_addr, buf)); - printf("yiaddr: %s\n", print_ip(dhcp->yiaddr.s_addr, buf)); - printf("siaddr: %s\n", print_ip(dhcp->siaddr.s_addr, buf)); - printf("giaddr: %s\n", print_ip(dhcp->giaddr.s_addr, buf)); - printf("chaddr: %s\n", print_mac(dhcp->chaddr, buf)); - printf("sname: %s.\n", dhcp->sname); - printf("file: %s.\n", dhcp->file); - - data = (uint8_t *)dhcp; - /* print options */ - j = DHCP_FIXED_NON_UDP; - /* XXX print cookie */ - j += DHCP_COOKIE_LEN; - while (j < data_len && data[j] != 255) { - printf("OPTION: %3d (%3d) %-26s", data[j], data[j + 1], - dhcp_options[data[j]]); - switch (data[j]) { - default: - printHexString(data + j + 2, data[j + 1]); - break; - case 0: /* padding */ - break; - case 1: /* Subnetmask */ - case 3: /* Routers */ - case 16: /* Swap server */ - case 28: /* Broadcast address */ - case 32: /* Router solicitation */ - case 50: /* Requested IP address */ - case 54: /* Server identifier */ - printf("%s", print_ip(*((uint32_t*)(data + j + 2)), buf)); - break; - - case 12: /* Hostname */ - case 14: /* Merit dump file */ - case 15: /* Domain name */ - case 17: /* Root Path */ - case 18: /* Extensions path */ - case 40: /* NIS domain */ - case 56: /* Message */ - case 62: /* Netware/IP domain name */ - case 64: /* NIS+ domain */ - case 66: /* TFTP server name */ - case 67: /* bootfile name */ - case 60: /* Vendor class identifier */ - case 86: /* NDS Tree name */ - case 87: /* NDS context */ - case 252: /* MSFT - WinSock Proxy Auto Detect */ - strlcpy(buf, (char*)&data[j + 2], data[j + 1]); - buf[data[j + 1]] = 0; - printf("%s", buf); - break; - - case 4: /* Time servers */ - case 5: /* Name servers */ - case 6: /* DNS server */ - case 7: /* Log server */ - case 8: /* Cookie server */ - case 9: /* LPR server */ - case 10: /* Impress server */ - case 11: /* Resource location server */ - case 41: /* NIS servers */ - case 42: /* NTP servers */ - case 44: /* NetBIOS name server */ - case 45: /* NetBIOS datagram distribution server */ - case 48: /* X Window System font server */ - case 49: /* X Window System display server */ - case 65: /* NIS+ servers */ - case 68: /* Mobile IP home agent */ - case 69: /* SMTP server */ - case 70: /* POP3 server */ - case 71: /* NNTP server */ - case 72: /* WWW server */ - case 73: /* Finger server */ - case 74: /* IRC server */ - case 75: /* StreetTalk server */ - case 76: /* StreetTalk directory assistance server */ - case 85: /* NDS server */ - case 150: /* CiscoCallManagerTFTP */ - for (i = 0; i < data[j + 1] / 4; i++) { - if (i != 0) - printf(","); - printf("%s", print_ip(*((uint32_t*)(data + j + 2 + i * 4)), buf)); - } - break; - - case 21: /* Policy filter */ - for (i = 0; i < data[j + 1] / 8; i++) { - if (i != 0) printf(","); - printf("%s/%s", - print_ip(*((uint32_t*)(data + j + 2 + i * 8)), buf), - print_ip(*((uint32_t*)((data + j + 2 + i * 8)+4)), buf+16) - ); - } - break; - - case 33: /* Static route */ - for (i = 0; i < data[j + 1] / 8; i++) { - if (i != 0) printf(","); - printf("%s %s", - print_ip(*((uint32_t*)(data + j + 2 + i * 8)), buf), - print_ip(*((uint32_t*)((data + j + 2 + i * 8)+4)), buf+16) - ); - } - break; - - case 25: /* Path MTU plateau table */ - for (i = 0; i < data[j + 1] / 2; i++) { - if (i != 0) printf(","); - print_word(data + j + 2 + i * 2); - } - break; - - case 13: /* bootfile size */ - case 22: /* Maximum datagram reassembly size */ - case 26: /* Interface MTU */ - case 57: /* Maximum DHCP message size */ - print_word(data + j + 2); - break; - - case 19: /* IP forwarding enabled/disable */ - case 20: /* Non-local source routing */ - case 27: /* All subnets local */ - case 29: /* Perform mask discovery */ - case 30: /* Mask supplier */ - case 31: /* Perform router discovery */ - case 34: /* Trailer encapsulation */ - case 39: /* TCP keepalive garbage */ - printf("%d (%s)", data[j + 2], enabledisable[data[j + 2]]); - break; - - case 23: /* Default IP TTL */ - print_time(data + j + 2, BITS8); - break; - - case 37: /* TCP default TTL */ - printf("%d", data[j+2]); - break; - - case 43: /* Vendor specific info */ - case 47: /* NetBIOS scope (no idea how it looks like) */ - printHexString(data + j + 2, data[j + 1]); - break; - - case 46: /* NetBIOS over TCP/IP node type */ - printf("%d (%s)", - data[j + 2], netbios_node_type[data[j + 2]]); - break; - - case 2: /* Time offset */ - case 24: /* Path MTU aging timeout */ - case 35: /* ARP cache timeout */ - case 38: /* TCP keepalive interval */ - case 51: /* IP address leasetime */ - case 58: /* T1 */ - case 59: /* T2 */ - print_time(data + j + 2, BITS32); - break; - - case 36: /* Ethernet encapsulation */ - printf("%d (%s)", - data[j + 2], - data[j +2 ] > sizeof(ethernet_encapsulation) ? - "*wrong value*" : - ethernet_encapsulation[data[j + 2]]); - break; - - case 52: /* Option overload */ - printf("%d (%s)", - data[j + 2], - data[j + 2] > sizeof(option_overload) ? - "*wrong value*" : - option_overload[data[j + 2]]); - break; - - case 53: /* DHCP message type */ - printf("%d (%s)", - data[j + 2], - data[j + 2] > sizeof(dhcp_message_types) ? - "*wrong value*" : - dhcp_message_types[data[j + 2]]); - break; - - case 55: /* Parameter Request List */ - printReqParmList(data + j + 2, data[j + 1]); - break; - - case 63: /* Netware/IP domain information */ - printHex(data + j + 2, data[j + 1]); - break; - - case 61: /* Client identifier */ - printHexColon(data + j + 2, data[j + 1]); - break; - - case 81: /* Client FQDN */ - printf("%d", data[j+2]); - printf("-"); - printf("%d", data[j+3]); - printf("-"); - printf("%d", data[j+4]); - printf(" "); - strlcpy(buf, (char*)&data[j + 5], data[j + 1] - 3); - buf[data[j + 1] - 3]=0; - printf("%s", buf); - break; - - case 82: /* Relay Agent Information */ - for (i = j + 2; i < j + data[j + 1]; ) { - printf("\n%-5s subopt: %3d (%3d) %-19s ", " ", - data[i], data[i + 1], - data[i] > sizeof(relayagent_suboptions) ? - "*wrong value*" : - relayagent_suboptions[data[i]]); - if (i + data[i + 1] > j + data[j + 1]) { - printf("*MALFORMED -- TOO LARGE*\n"); - break; - } - printHexString(data + i + 2, data[i + 1]); - i += data[i + 1] + 2; - } - break; + char buf[1024]; + uint8_t *data; + int i, j; + + puts("---------------------------------------------------------------------------"); + printf("op: %d (%s)\n", dhcp->op, + dhcp->op == 1 ? "BOOTREQUEST" : (dhcp->op == 2 ? "BOOTREPLY" : "illegal")); + printf("htype: %d (%s)\n", dhcp->htype, dhcp->htype == 1 ? "Ethernet" : ""); + printf("hlen: %d\n", dhcp->hlen); + printf("hops: %d\n", dhcp->hops); + printf("xid: %s\n", print_xid(dhcp->xid, buf)); + printf("secs: %d\n", dhcp->secs); + printf("flags: 0x%X\n", dhcp->flags); + printf("ciaddr: %s\n", print_ip(dhcp->ciaddr.s_addr, buf)); + printf("yiaddr: %s\n", print_ip(dhcp->yiaddr.s_addr, buf)); + printf("siaddr: %s\n", print_ip(dhcp->siaddr.s_addr, buf)); + printf("giaddr: %s\n", print_ip(dhcp->giaddr.s_addr, buf)); + printf("chaddr: %s\n", print_mac(dhcp->chaddr, buf)); + printf("sname: %s.\n", dhcp->sname); + printf("file: %s.\n", dhcp->file); + + data = (uint8_t *)dhcp; + /* print options */ + j = DHCP_FIXED_NON_UDP; + /* XXX print cookie */ + j += DHCP_COOKIE_LEN; + while (j < data_len && data[j] != 255) { + printf("OPTION: %3d (%3d) %-26s", data[j], data[j + 1], + dhcp_options[data[j]]); + switch (data[j]) { + default: + printHexString(data + j + 2, data[j + 1]); + break; + case 0: /* padding */ + break; + case 1: /* Subnetmask */ + case 3: /* Routers */ + case 16: /* Swap server */ + case 28: /* Broadcast address */ + case 32: /* Router solicitation */ + case 50: /* Requested IP address */ + case 54: /* Server identifier */ + printf("%s", print_ip(*((uint32_t *)(data + j + 2)), buf)); + break; + + case 12: /* Hostname */ + case 14: /* Merit dump file */ + case 15: /* Domain name */ + case 17: /* Root Path */ + case 18: /* Extensions path */ + case 40: /* NIS domain */ + case 56: /* Message */ + case 62: /* Netware/IP domain name */ + case 64: /* NIS+ domain */ + case 66: /* TFTP server name */ + case 67: /* bootfile name */ + case 60: /* Vendor class identifier */ + case 86: /* NDS Tree name */ + case 87: /* NDS context */ + case 252: /* MSFT - WinSock Proxy Auto Detect */ + strlcpy(buf, (char *)&data[j + 2], data[j + 1]); + buf[data[j + 1]] = 0; + printf("%s", buf); + break; + + case 4: /* Time servers */ + case 5: /* Name servers */ + case 6: /* DNS server */ + case 7: /* Log server */ + case 8: /* Cookie server */ + case 9: /* LPR server */ + case 10: /* Impress server */ + case 11: /* Resource location server */ + case 41: /* NIS servers */ + case 42: /* NTP servers */ + case 44: /* NetBIOS name server */ + case 45: /* NetBIOS datagram distribution server */ + case 48: /* X Window System font server */ + case 49: /* X Window System display server */ + case 65: /* NIS+ servers */ + case 68: /* Mobile IP home agent */ + case 69: /* SMTP server */ + case 70: /* POP3 server */ + case 71: /* NNTP server */ + case 72: /* WWW server */ + case 73: /* Finger server */ + case 74: /* IRC server */ + case 75: /* StreetTalk server */ + case 76: /* StreetTalk directory assistance server */ + case 85: /* NDS server */ + case 150: /* CiscoCallManagerTFTP */ + for (i = 0; i < data[j + 1] / 4; i++) { + if (i != 0) + printf(","); + printf("%s", print_ip(*((uint32_t *)(data + j + 2 + i * 4)), buf)); + } + break; + + case 21: /* Policy filter */ + for (i = 0; i < data[j + 1] / 8; i++) { + if (i != 0) + printf(","); + printf("%s/%s", + print_ip(*((uint32_t *)(data + j + 2 + i * 8)), buf), + print_ip(*((uint32_t *)((data + j + 2 + i * 8) + 4)), buf + 16) + ); + } + break; + + case 33: /* Static route */ + for (i = 0; i < data[j + 1] / 8; i++) { + if (i != 0) + printf(","); + printf("%s %s", + print_ip(*((uint32_t *)(data + j + 2 + i * 8)), buf), + print_ip(*((uint32_t *)((data + j + 2 + i * 8) + 4)), buf + 16) + ); + } + break; + + case 25: /* Path MTU plateau table */ + for (i = 0; i < data[j + 1] / 2; i++) { + if (i != 0) + printf(","); + print_word(data + j + 2 + i * 2); + } + break; + + case 13: /* bootfile size */ + case 22: /* Maximum datagram reassembly size */ + case 26: /* Interface MTU */ + case 57: /* Maximum DHCP message size */ + print_word(data + j + 2); + break; + + case 19: /* IP forwarding enabled/disable */ + case 20: /* Non-local source routing */ + case 27: /* All subnets local */ + case 29: /* Perform mask discovery */ + case 30: /* Mask supplier */ + case 31: /* Perform router discovery */ + case 34: /* Trailer encapsulation */ + case 39: /* TCP keepalive garbage */ + printf("%d (%s)", data[j + 2], enabledisable[data[j + 2]]); + break; + + case 23: /* Default IP TTL */ + print_time(data + j + 2, BITS8); + break; + + case 37: /* TCP default TTL */ + printf("%d", data[j + 2]); + break; + + case 43: /* Vendor specific info */ + case 47: /* NetBIOS scope (no idea how it looks like) */ + printHexString(data + j + 2, data[j + 1]); + break; + + case 46: /* NetBIOS over TCP/IP node type */ + printf("%d (%s)", + data[j + 2], netbios_node_type[data[j + 2]]); + break; + + case 2: /* Time offset */ + case 24: /* Path MTU aging timeout */ + case 35: /* ARP cache timeout */ + case 38: /* TCP keepalive interval */ + case 51: /* IP address leasetime */ + case 58: /* T1 */ + case 59: /* T2 */ + print_time(data + j + 2, BITS32); + break; + + case 36: /* Ethernet encapsulation */ + printf("%d (%s)", + data[j + 2], + data[j + 2] > sizeof(ethernet_encapsulation) ? + "*wrong value*" : + ethernet_encapsulation[data[j + 2]]); + break; + + case 52: /* Option overload */ + printf("%d (%s)", + data[j + 2], + data[j + 2] > sizeof(option_overload) ? + "*wrong value*" : + option_overload[data[j + 2]]); + break; + + case 53: /* DHCP message type */ + printf("%d (%s)", + data[j + 2], + data[j + 2] > sizeof(dhcp_message_types) ? + "*wrong value*" : + dhcp_message_types[data[j + 2]]); + break; + + case 55: /* Parameter Request List */ + printReqParmList(data + j + 2, data[j + 1]); + break; + + case 63: /* Netware/IP domain information */ + printHex(data + j + 2, data[j + 1]); + break; + + case 61: /* Client identifier */ + printHexColon(data + j + 2, data[j + 1]); + break; + + case 81: /* Client FQDN */ + printf("%d", data[j + 2]); + printf("-"); + printf("%d", data[j + 3]); + printf("-"); + printf("%d", data[j + 4]); + printf(" "); + strlcpy(buf, (char *)&data[j + 5], data[j + 1] - 3); + buf[data[j + 1] - 3] = 0; + printf("%s", buf); + break; + + case 82: /* Relay Agent Information */ + for (i = j + 2; i < j + data[j + 1];) { + printf("\n%-5s subopt: %3d (%3d) %-19s ", " ", + data[i], data[i + 1], + data[i] > sizeof(relayagent_suboptions) ? + "*wrong value*" : + relayagent_suboptions[data[i]]); + if (i + data[i + 1] > j + data[j + 1]) { + printf("*MALFORMED -- TOO LARGE*\n"); + break; + } + printHexString(data + i + 2, data[i + 1]); + i += data[i + 1] + 2; + } + break; + } + printf("\n"); + if (data[j] == 0) /* padding */ + j++; + else + j += data[j + 1] + 2; } - printf("\n"); - if (data[j]==0) /* padding */ - j++; - else - j+=data[j + 1] + 2; - } - puts("---------------------------------------------------------------------------\n"); + puts("---------------------------------------------------------------------------\n"); } int log_plugin_client_request(const struct interface *intf, - uint8_t **packet, size_t *psize) + uint8_t **packet, size_t *psize) { - char buf[18*2+11], timebuf[16], logbuf[256]; - struct dhcp_packet *dhcp; - - if(debug) { - dhcp = (struct dhcp_packet *)(*packet+ETHER_HDR_LEN+DHCP_UDP_OVERHEAD); - log_plugin_get_time(timebuf); - sprintf(logbuf, "%s request on %s XID: %s %s -> %s (%zu bytes)", timebuf, - intf->name, - print_xid(dhcp->xid, buf), - print_mac(((struct ether_header*)*packet)->ether_shost, buf+11), - print_mac(((struct ether_header*)*packet)->ether_dhost, buf+29), - *psize - (ETHER_HDR_LEN+DHCP_UDP_OVERHEAD) - ); - puts(logbuf); - if(detailed) - print_dhcp_packet(dhcp, *psize-(ETHER_HDR_LEN+DHCP_UDP_OVERHEAD)); - } - return 1; + char buf[18 * 2 + 11], timebuf[16], logbuf[256]; + struct dhcp_packet *dhcp; + + if (debug) { + dhcp = (struct dhcp_packet *)(*packet + ETHER_HDR_LEN + DHCP_UDP_OVERHEAD); + log_plugin_get_time(timebuf); + sprintf(logbuf, "%s request on %s XID: %s %s -> %s (%zu bytes)", timebuf, + intf->name, + print_xid(dhcp->xid, buf), + print_mac(((struct ether_header *)*packet)->ether_shost, buf + 11), + print_mac(((struct ether_header *)*packet)->ether_dhost, buf + 29), + *psize - (ETHER_HDR_LEN + DHCP_UDP_OVERHEAD) + ); + puts(logbuf); + if (detailed) + print_dhcp_packet(dhcp, *psize - (ETHER_HDR_LEN + DHCP_UDP_OVERHEAD)); + } + return 1; } int log_plugin_send_to_server(const struct sockaddr_in *server, - uint8_t **packet, size_t *psize) + uint8_t **packet, size_t *psize) { - char buf[16+11], timebuf[16], logbuf[256]; - struct dhcp_packet *dhcp; - - if(debug && !print_only_incoming) { - dhcp = (struct dhcp_packet *)*packet; - log_plugin_get_time(timebuf); - sprintf(logbuf, "%s send XID: %s to server %s (%zu bytes)", timebuf, - print_xid(dhcp->xid, buf), - print_ip(server->sin_addr.s_addr, buf+11), - *psize - ); - puts(logbuf); - if(detailed) - print_dhcp_packet(dhcp, *psize); - } - return 1; + char buf[16 + 11], timebuf[16], logbuf[256]; + struct dhcp_packet *dhcp; + + if (debug && !print_only_incoming) { + dhcp = (struct dhcp_packet *)*packet; + log_plugin_get_time(timebuf); + sprintf(logbuf, "%s send XID: %s to server %s (%zu bytes)", timebuf, + print_xid(dhcp->xid, buf), + print_ip(server->sin_addr.s_addr, buf + 11), + *psize + ); + puts(logbuf); + if (detailed) + print_dhcp_packet(dhcp, *psize); + } + return 1; } int log_plugin_server_answer(const struct sockaddr_in *server, uint8_t **packet, - size_t *psize) + size_t *psize) { - char buf[16+11], timebuf[16], logbuf[256]; - struct dhcp_packet *dhcp; - - if(debug) { - dhcp = (struct dhcp_packet *)*packet; - log_plugin_get_time(timebuf); - sprintf(logbuf, "%s reply from server (%s) XID: %s (%zu bytes)", timebuf, - print_ip(server->sin_addr.s_addr, buf), - print_xid(dhcp->xid, buf+16), - *psize - ); - puts(logbuf); - if(detailed) - print_dhcp_packet(dhcp, *psize); - } - return 1; + char buf[16 + 11], timebuf[16], logbuf[256]; + struct dhcp_packet *dhcp; + + if (debug) { + dhcp = (struct dhcp_packet *)*packet; + log_plugin_get_time(timebuf); + sprintf(logbuf, "%s reply from server (%s) XID: %s (%zu bytes)", timebuf, + print_ip(server->sin_addr.s_addr, buf), + print_xid(dhcp->xid, buf + 16), + *psize + ); + puts(logbuf); + if (detailed) + print_dhcp_packet(dhcp, *psize); + } + return 1; } -int log_plugin_send_to_client(const struct sockaddr_in *server, - const struct interface *intf, uint8_t **packet, - size_t *psize) +int +log_plugin_send_to_client(const struct sockaddr_in *server, + const struct interface *intf, uint8_t **packet, + size_t *psize) { - char buf[11+16+18], timebuf[16], logbuf[256]; - struct ip *ip; - struct udphdr *udp; - struct dhcp_packet *dhcp; - - if(debug && !print_only_incoming) { - ip = (struct ip *)(*packet+ETHER_HDR_LEN); - udp = (struct udphdr *)(*packet+ETHER_HDR_LEN+sizeof(struct ip)); - dhcp = (struct dhcp_packet *)(*packet+ETHER_HDR_LEN+DHCP_UDP_OVERHEAD); - - log_plugin_get_time(timebuf); - sprintf(logbuf, "%s (from %s) send XID: %s for %s via %s (%zu bytes)", timebuf, - print_ip(server->sin_addr.s_addr, buf), - print_xid(dhcp->xid, buf+16), print_mac(dhcp->chaddr, buf+27), - intf->name, *psize - (ETHER_HDR_LEN+DHCP_UDP_OVERHEAD) - ); - puts(logbuf); - if(detailed) - print_dhcp_packet(dhcp, *psize-(ETHER_HDR_LEN+DHCP_UDP_OVERHEAD)); - } - return 1; + char buf[11 + 16 + 18], timebuf[16], logbuf[256]; + struct ip *ip; + struct udphdr *udp; + struct dhcp_packet *dhcp; + + if (debug && !print_only_incoming) { + ip = (struct ip *)(*packet + ETHER_HDR_LEN); + udp = (struct udphdr *)(*packet + ETHER_HDR_LEN + sizeof(struct ip)); + dhcp = (struct dhcp_packet *)(*packet + ETHER_HDR_LEN + DHCP_UDP_OVERHEAD); + + log_plugin_get_time(timebuf); + sprintf(logbuf, "%s (from %s) send XID: %s for %s via %s (%zu bytes)", timebuf, + print_ip(server->sin_addr.s_addr, buf), + print_xid(dhcp->xid, buf + 16), print_mac(dhcp->chaddr, buf + 27), + intf->name, *psize - (ETHER_HDR_LEN + DHCP_UDP_OVERHEAD) + ); + puts(logbuf); + if (detailed) + print_dhcp_packet(dhcp, *psize - (ETHER_HDR_LEN + DHCP_UDP_OVERHEAD)); + } + return 1; } struct plugin_data log_plugin = { "log", log_plugin_init, - NULL, /* no destroy() function */ + NULL, /* no destroy() function */ log_plugin_client_request, log_plugin_send_to_server, log_plugin_server_answer, diff --git a/net_utils.c b/net_utils.c index 74d776c..66eb0b2 100644 --- a/net_utils.c +++ b/net_utils.c @@ -1,31 +1,28 @@ -/* - * Copyright (c) 2007-2012 Sergey Matveychuk - * Yandex, LLC. All rights reserved. - * +/* Copyright (c) 2007-2012 Sergey Matveychuk Yandex, LLC. All rights + * reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 4. Neither the name + * of the company nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ + * SUCH DAMAGE. */ #include #include @@ -43,58 +40,54 @@ int get_mac(char *if_name, char *if_mac) { - struct ifaddrs *ifaphead, *ifap; - int found=0; - struct sockaddr_dl *sdl=NULL; + struct ifaddrs *ifaphead, *ifap; + int found = 0; + struct sockaddr_dl *sdl = NULL; - if(getifaddrs(&ifaphead) != 0) - errx(EX_RES, "getifaddrs: %s", strerror(errno)); + if (getifaddrs(&ifaphead) != 0) + errx(EX_RES, "getifaddrs: %s", strerror(errno)); - for(ifap = ifaphead; ifap && !found; ifap = ifap->ifa_next) - if(strcmp(ifap->ifa_name, if_name) == 0) { - found = 1; - sdl = (struct sockaddr_dl *)ifap->ifa_addr; - if(sdl) - memcpy(if_mac, LLADDR(sdl), sdl->sdl_alen); + for (ifap = ifaphead; ifap && !found; ifap = ifap->ifa_next) + if (strcmp(ifap->ifa_name, if_name) == 0) { + found = 1; + sdl = (struct sockaddr_dl *)ifap->ifa_addr; + if (sdl) + memcpy(if_mac, LLADDR(sdl), sdl->sdl_alen); + } + freeifaddrs(ifaphead); + if (!found) { + logd(LOG_DEBUG, "can't find mac for interface %s", if_name); + return 0; } - - freeifaddrs(ifaphead); - if(!found) { - logd(LOG_DEBUG, "can't find mac for interface %s", if_name); - return 0; - } - - return 1; + return 1; } -int +int get_ip(char *iname, ip_addr_t *ip, ip_addr_t *mask) { - int s; - struct ifreq ifr; - struct sockaddr_in *saddr; + int s; + struct ifreq ifr; + struct sockaddr_in *saddr; - if((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) - errx(EX_RES, "get_ip: socket: %s", strerror(errno)); + if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + errx(EX_RES, "get_ip: socket: %s", strerror(errno)); - strlcpy(ifr.ifr_name, iname, sizeof(ifr.ifr_name)); - if(ioctl(s, SIOCGIFADDR, &ifr) < 0) { - close(s); - logd(LOG_DEBUG, "Can't get IP for %s", iname); - return 0; - } + strlcpy(ifr.ifr_name, iname, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { + close(s); + logd(LOG_DEBUG, "Can't get IP for %s", iname); + return 0; + } + saddr = (struct sockaddr_in *)&ifr.ifr_addr; + memcpy(ip, &saddr->sin_addr.s_addr, sizeof(ip_addr_t)); - saddr = (struct sockaddr_in*)&ifr.ifr_addr; - memcpy(ip, &saddr->sin_addr.s_addr, sizeof(ip_addr_t)); + if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) { + close(s); + logd(LOG_DEBUG, "Can't get netmask for %s", iname); + return 0; + } + memcpy(mask, &saddr->sin_addr.s_addr, sizeof(ip_addr_t)); - if(ioctl(s, SIOCGIFNETMASK, &ifr) < 0) { close(s); - logd(LOG_DEBUG, "Can't get netmask for %s", iname); - return 0; - } - - memcpy(mask, &saddr->sin_addr.s_addr, sizeof(ip_addr_t)); - - close(s); - return 1; + return 1; } diff --git a/option82_plugin.c b/option82_plugin.c index 1960b13..9e43660 100644 --- a/option82_plugin.c +++ b/option82_plugin.c @@ -1,31 +1,28 @@ -/* - * Copyright (c) 2007-2012 Sergey Matveychuk - * Yandex, LLC. All rights reserved. - * +/* Copyright (c) 2007-2012 Sergey Matveychuk Yandex, LLC. All rights + * reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 4. Neither the name + * of the company nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ + * SUCH DAMAGE. */ #include #include @@ -34,303 +31,294 @@ #include "dhcprelya.h" static char rid[255]; -static int rid_len, drop_untrusted=1, - never_strip_answer=0, always_strip_answer=0; +static int rid_len, drop_untrusted = 1, never_strip_answer = 0, always_strip_answer = 0; STAILQ_HEAD(thead, trusted_circuits) trusted_head; struct trusted_circuits { - uint8_t *id; - int len; + uint8_t *id; + int len; - STAILQ_ENTRY(trusted_circuits) next; + STAILQ_ENTRY(trusted_circuits) next; }; -/* - * returns: - * NULL if optin82 was not found. - * *optins point to End-Of-Options mark (255) - * or pointer to option82 - */ +/* returns: NULL if optin82 was not found. *optins point to End-Of-Options + * mark (255) or pointer to option82 */ uint8_t * find_option82(uint8_t *options) { - uint8_t *p = NULL; - - do { - switch(*options) { - case 0: - options++; - break; - default: - options += options[1] + 2; - } - } while(*options != 255 && *options != 82); + uint8_t *p = NULL; + + do { + switch (*options) { + case 0: + options++; + break; + default: + options += options[1] + 2; + } + } while (*options != 255 && *options != 82); - if(*options == 82) - p = options; + if (*options == 82) + p = options; - return p; + return p; } int option82_plugin_init(plugin_options_head_t *options_head) { - struct plugin_options *opts, *opts_tmp; - int i, n, rid_set=0; - char *p, *p1; - struct trusted_circuits *tc_entry; + struct plugin_options *opts, *opts_tmp; + int i, n, rid_set = 0; + char *p, *p1; + struct trusted_circuits *tc_entry; - STAILQ_INIT(&trusted_head); + STAILQ_INIT(&trusted_head); - SLIST_FOREACH_SAFE(opts, options_head, next, opts_tmp) { - if((p = strchr(opts->option_line, '=')) == NULL) { - logd(LOG_ERR, "option82_plugin: Syntax error at line: %s", opts->option_line); - return 0; - } - *p = '\0'; p++; - if(strcasecmp(opts->option_line, "drop_untrusted") == 0) { - if((drop_untrusted=get_bool_value(p)) == -1) { - logd(LOG_ERR, "option82_plugin: Syntex error in option value at line: %s", opts->option_line); - return 0; - } - } else if(strcasecmp(opts->option_line, "remote_id") == 0) { - rid_set = 1; - rid_len = 0; - /* is a string */ - if(*p == '"') { - p++; - for(i=0; *p != '"' && *p != '\0'; p++,i++) - rid[i] = *p; - if(*p != '"') { - logd(LOG_ERR, "option82_plugin: Syntex error in option value at line: %s", opts->option_line); - return 0; - } - } else if(strcasecmp(p, "0x") == 0) { - p += 2; - logd(LOG_ERR, "option82_plugin: hexadecimal is not supported yet at line: %s", opts->option_line); - return 0; - } else { - logd(LOG_ERR, "option82_plugin: Syntex error in option value at line: %s", opts->option_line); - return 0; - } - } else if(strcasecmp(opts->option_line, "never_strip_answer") == 0) { - if((never_strip_answer=get_bool_value(p)) == -1) { - logd(LOG_ERR, "option82_plugin: Syntex error in option value at line: %s", opts->option_line); - return 0; - } - } else if(strcasecmp(opts->option_line, "always_strip_answer") == 0) { - if((always_strip_answer=get_bool_value(p)) == -1) { - logd(LOG_ERR, "option82_plugin: Syntex error in option value at line: %s", opts->option_line); - return 0; - } - if(never_strip_answer && always_strip_answer) { - logd(LOG_ERR, "option82_plugin: options never_strip_answer and always_strip_answer are mutually exclusive"); - return 0; - } - } else if(strcasecmp(opts->option_line, "trusted_circuits") == 0) { - n=1; - while((p1 = strsep(&p, " \t")) != NULL) { - if(*p1 == '"') { - p1++; - tc_entry = malloc(sizeof(struct trusted_circuits)); - if(tc_entry == NULL) { - logd(LOG_ERR, "option82_plugin: malloc error"); - return 0; - } - tc_entry->id = malloc(strlen(p1)); - if(tc_entry->id == NULL) { - logd(LOG_ERR, "option82_plugin: malloc error"); - return 0; - } - for(i=0; *p1 != '\0'; i++,p1++) - tc_entry->id[i] = *p1; - i--; - if(tc_entry->id[i] != '"') { - logd(LOG_ERR, "option82_plugin: value syntax error at line %d", opts->option_line); + SLIST_FOREACH_SAFE(opts, options_head, next, opts_tmp) { + if ((p = strchr(opts->option_line, '=')) == NULL) { + logd(LOG_ERR, "option82_plugin: Syntax error at line: %s", opts->option_line); return 0; - } - tc_entry->id[i] = '\0'; - logd(LOG_DEBUG, "trusted circuit #%d: %s", n, tc_entry->id); - tc_entry->len = strlen((char*)tc_entry->id); - STAILQ_INSERT_TAIL(&trusted_head, tc_entry, next); - n++; + } + *p = '\0'; + p++; + if (strcasecmp(opts->option_line, "drop_untrusted") == 0) { + if ((drop_untrusted = get_bool_value(p)) == -1) { + logd(LOG_ERR, "option82_plugin: Syntex error in option value at line: %s", opts->option_line); + return 0; + } + } else if (strcasecmp(opts->option_line, "remote_id") == 0) { + rid_set = 1; + rid_len = 0; + /* is a string */ + if (*p == '"') { + p++; + for (i = 0; *p != '"' && *p != '\0'; p++, i++) + rid[i] = *p; + if (*p != '"') { + logd(LOG_ERR, "option82_plugin: Syntex error in option value at line: %s", opts->option_line); + return 0; + } + } else if (strcasecmp(p, "0x") == 0) { + p += 2; + logd(LOG_ERR, "option82_plugin: hexadecimal is not supported yet at line: %s", opts->option_line); + return 0; + } else { + logd(LOG_ERR, "option82_plugin: Syntex error in option value at line: %s", opts->option_line); + return 0; + } + } else if (strcasecmp(opts->option_line, "never_strip_answer") == 0) { + if ((never_strip_answer = get_bool_value(p)) == -1) { + logd(LOG_ERR, "option82_plugin: Syntex error in option value at line: %s", opts->option_line); + return 0; + } + } else if (strcasecmp(opts->option_line, "always_strip_answer") == 0) { + if ((always_strip_answer = get_bool_value(p)) == -1) { + logd(LOG_ERR, "option82_plugin: Syntex error in option value at line: %s", opts->option_line); + return 0; + } + if (never_strip_answer && always_strip_answer) { + logd(LOG_ERR, "option82_plugin: options never_strip_answer and always_strip_answer are mutually exclusive"); + return 0; + } + } else if (strcasecmp(opts->option_line, "trusted_circuits") == 0) { + n = 1; + while ((p1 = strsep(&p, " \t")) != NULL) { + if (*p1 == '"') { + p1++; + tc_entry = malloc(sizeof(struct trusted_circuits)); + if (tc_entry == NULL) { + logd(LOG_ERR, "option82_plugin: malloc error"); + return 0; + } + tc_entry->id = malloc(strlen(p1)); + if (tc_entry->id == NULL) { + logd(LOG_ERR, "option82_plugin: malloc error"); + return 0; + } + for (i = 0; *p1 != '\0'; i++, p1++) + tc_entry->id[i] = *p1; + i--; + if (tc_entry->id[i] != '"') { + logd(LOG_ERR, "option82_plugin: value syntax error at line %d", opts->option_line); + return 0; + } + tc_entry->id[i] = '\0'; + logd(LOG_DEBUG, "trusted circuit #%d: %s", n, tc_entry->id); + tc_entry->len = strlen((char *)tc_entry->id); + STAILQ_INSERT_TAIL(&trusted_head, tc_entry, next); + n++; + } else { + if (strncasecmp(p1, "0x", 2) == 0) + logd(LOG_ERR, "option82_plugin: hexadecial is not supported yet at line: %d", opts->option_line); + else + logd(LOG_ERR, "option82_plugin: value syntax error at line %d", opts->option_line); + return 0; + } + } } else { - if(strncasecmp(p1, "0x", 2) == 0) - logd(LOG_ERR, "option82_plugin: hexadecial is not supported yet at line: %d", opts->option_line); - else - logd(LOG_ERR, "option82_plugin: value syntax error at line %d", opts->option_line); - return 0; + logd(LOG_ERR, "option82_plugin: Unknown option at line: %s", opts->option_line); + return 0; } - } - } else { - logd(LOG_ERR, "option82_plugin: Unknown option at line: %s", opts->option_line); - return 0; + free(opts->option_line); + SLIST_REMOVE(options_head, opts, plugin_options, next); + free(opts); } - free(opts->option_line); - SLIST_REMOVE(options_head, opts, plugin_options, next); - free(opts); - } - if(!rid_set) { - if(gethostname(rid, sizeof(rid)) == -1) { - logd(LOG_ERR, "option82_plugin: Can't get a hostname"); - return 0; + if (!rid_set) { + if (gethostname(rid, sizeof(rid)) == -1) { + logd(LOG_ERR, "option82_plugin: Can't get a hostname"); + return 0; + } + rid_len = strlen(rid); } - rid_len = strlen(rid); - } - logd(LOG_DEBUG, "option82_plugin: Agent Remote ID: %s", rid); - return 1; + logd(LOG_DEBUG, "option82_plugin: Agent Remote ID: %s", rid); + return 1; } int option82_plugin_client_request(const struct interface *intf, - uint8_t **packet, size_t *psize) + uint8_t **packet, size_t *psize) { - struct dhcp_packet *dhcp; - uint8_t *buf, *p, *opt; - int intf_name_len, match; - struct trusted_circuits *tc_entry; - - dhcp = (struct dhcp_packet *)(*packet+ETHER_HDR_LEN+DHCP_UDP_OVERHEAD); - p = dhcp->options; - p += DHCP_COOKIE_LEN; - - opt = find_option82(p); - /* XXX discard if GIADDR spoofing (our address) */ - if(*((ip_addr_t*)&dhcp->giaddr) == 0 && opt != NULL) { - logd(LOG_ERR, "option82_plugin: got a packet from an agent but GIADDR == 0. Dropped."); - return 0; - } - - /* - * if we already have option82, check for trusted circuits. - * we'll not add own option82 if it's already there. - */ - if(opt) { - match=0; - STAILQ_FOREACH(tc_entry, &trusted_head, next) { - if(tc_entry->len == rid_len && memcmp(tc_entry->id, rid, rid_len) == 0) - match = 1; - } - if(!match) { - logd(LOG_DEBUG, "option82_plugin: got a packet with option82 but from unknown circuit. Dropped."); - return 0; - } - } else { - /* Go to end of options mark */ - while(*p != 255 && p-*packet <= *psize) { - p++; - } - - /* Not found. Bad packet. */ - if(p-*packet >= *psize) { - logd(LOG_ERR, "option82_plugin: Bad options format"); - return 0; + struct dhcp_packet *dhcp; + uint8_t *buf, *p, *opt; + int intf_name_len, match; + struct trusted_circuits *tc_entry; + + dhcp = (struct dhcp_packet *)(*packet + ETHER_HDR_LEN + DHCP_UDP_OVERHEAD); + p = dhcp->options; + p += DHCP_COOKIE_LEN; + + opt = find_option82(p); + /* XXX discard if GIADDR spoofing (our address) */ + if (*((ip_addr_t *)&dhcp->giaddr) == 0 && opt != NULL) { + logd(LOG_ERR, "option82_plugin: got a packet from an agent but GIADDR == 0. Dropped."); + return 0; } + /* if we already have option82, check for trusted circuits. we'll not + * add own option82 if it's already there. */ + if (opt) { + match = 0; + STAILQ_FOREACH(tc_entry, &trusted_head, next) { + if (tc_entry->len == rid_len && memcmp(tc_entry->id, rid, rid_len) == 0) + match = 1; + } + if (!match) { + logd(LOG_DEBUG, "option82_plugin: got a packet with option82 but from unknown circuit. Dropped."); + return 0; + } + } else { + /* Go to end of options mark */ + while (*p != 255 && p - *packet <= *psize) { + p++; + } - intf_name_len = strlen(intf->name); + /* Not found. Bad packet. */ + if (p - *packet >= *psize) { + logd(LOG_ERR, "option82_plugin: Bad options format"); + return 0; + } + intf_name_len = strlen(intf->name); - /* RFC3046 requires this check */ - if(*psize+4+intf_name_len+rid_len > max_packet_size) { - logd(LOG_ERR, "option82_plugin: a packet will oversided after adding options82. Passed without changes."); - return 1; - } - buf = malloc(*psize + intf_name_len + rid_len + 6); - if(buf == NULL) { - logd(LOG_ERR, "option82_plugin: malloc error"); - return 0; + /* RFC3046 requires this check */ + if (*psize + 4 + intf_name_len + rid_len > max_packet_size) { + logd(LOG_ERR, "option82_plugin: a packet will oversided after adding options82. Passed without changes."); + return 1; + } + buf = malloc(*psize + intf_name_len + rid_len + 6); + if (buf == NULL) { + logd(LOG_ERR, "option82_plugin: malloc error"); + return 0; + } + memset(buf, 0, *psize + intf_name_len + rid_len + 6); + memcpy(buf, *packet, *psize); + + p = buf + (p - *packet); + + *(p++) = 82; + *(p++) = 4 + intf_name_len + rid_len; + *(p++) = 1; + *(p++) = intf_name_len; + memcpy(p, intf->name, intf_name_len); + p += intf_name_len; + + *(p++) = 2; + *(p++) = rid_len; + memcpy(p, rid, rid_len); + p += rid_len; + /* End of options */ + *p = 255; + + p = *packet; + *packet = buf; + free(p); + *psize = *psize + intf_name_len + rid_len + 6; } - memset(buf, 0, *psize + intf_name_len + rid_len + 6); - memcpy(buf, *packet, *psize); - - p = buf + (p-*packet); - - *(p++) = 82; - *(p++) = 4 + intf_name_len + rid_len; - *(p++) = 1; - *(p++) = intf_name_len; - memcpy(p, intf->name, intf_name_len); - p += intf_name_len; - - *(p++) = 2; - *(p++) = rid_len; - memcpy(p, rid, rid_len); - p += rid_len; - /* End of options */ - *p = 255; - p = *packet; - *packet = buf; - free(p); - *psize = *psize + intf_name_len + rid_len + 6; - } - - return 1; + return 1; } -int option82_plugin_send_to_client(const struct sockaddr_in *server, - const struct interface *intf, uint8_t **packet, - size_t *psize) +int +option82_plugin_send_to_client(const struct sockaddr_in *server, + const struct interface *intf, uint8_t **packet, + size_t *psize) { - struct dhcp_packet *dhcp; - struct ip *ip; - struct udphdr *udp; - uint8_t *p, *opt; - int rlen, opt_size = 0, match, need_strip=0; - struct trusted_circuits *tc_entry; - - dhcp = (struct dhcp_packet *)(*packet+ETHER_HDR_LEN+DHCP_UDP_OVERHEAD); - ip = (struct ip *)(*packet+ETHER_HDR_LEN); - udp = (struct udphdr *)(*packet+ETHER_HDR_LEN+sizeof(struct ip)); - - opt = find_option82(dhcp->options + DHCP_COOKIE_LEN); - /* We don't find option82, drop the packet */ - if(opt == NULL) - return 0; - /* Find Remote ID sub-option */ - p = opt + 2; - if(*p != 1 && *p !=2) { - logd(LOG_ERR, "option82_plugin: bad sub-option. The packet dropped."); - return 0; - } - if(*p == 1) - p += *(p+1)+2; - p++; - rlen = *p++; - /* Check if Remote ID is our one */ - match=0; - if(rlen == rid_len && memcmp(rid, p, rid_len) == 0) - match = 1; - - /* it's not our. check for trusted */ - if(!match) { - match=0; - STAILQ_FOREACH(tc_entry, &trusted_head, next) { - if(tc_entry->len == rlen && memcmp(tc_entry->id, p, rlen) == 0) - match = 1; - } - if(!match) { - *(p+rlen) = '\0'; - logd(LOG_DEBUG, "option82_plugin: an answer from untrusted circuit: %s. Ignored", p); - return 0; + struct dhcp_packet *dhcp; + struct ip *ip; + struct udphdr *udp; + uint8_t *p, *opt; + int rlen, opt_size = 0, match, need_strip = 0; + struct trusted_circuits *tc_entry; + + dhcp = (struct dhcp_packet *)(*packet + ETHER_HDR_LEN + DHCP_UDP_OVERHEAD); + ip = (struct ip *)(*packet + ETHER_HDR_LEN); + udp = (struct udphdr *)(*packet + ETHER_HDR_LEN + sizeof(struct ip)); + + opt = find_option82(dhcp->options + DHCP_COOKIE_LEN); + /* We don't find option82, drop the packet */ + if (opt == NULL) + return 0; + /* Find Remote ID sub-option */ + p = opt + 2; + if (*p != 1 && *p != 2) { + logd(LOG_ERR, "option82_plugin: bad sub-option. The packet dropped."); + return 0; } - need_strip = 0; - } else - if(!never_strip_answer) - need_strip = 1; - - /* strip option82 */ - if(need_strip || always_strip_answer) { - opt_size = opt[1] + 2; - memmove(opt, opt + opt_size, *psize - (opt+opt_size - *packet)); - *psize -= opt_size; - udp->uh_ulen = htons(ntohs(udp->uh_ulen) - opt_size); - ip->ip_len = htons(ntohs(ip->ip_len) - opt_size); - ip->ip_sum = 0; - ip->ip_sum = htons(ip_checksum((const char*)ip, sizeof(struct ip))); - } + if (*p == 1) + p += *(p + 1) + 2; + p++; + rlen = *p++; + /* Check if Remote ID is our one */ + match = 0; + if (rlen == rid_len && memcmp(rid, p, rid_len) == 0) + match = 1; - return 1; + /* it's not our. check for trusted */ + if (!match) { + match = 0; + STAILQ_FOREACH(tc_entry, &trusted_head, next) { + if (tc_entry->len == rlen && memcmp(tc_entry->id, p, rlen) == 0) + match = 1; + } + if (!match) { + *(p + rlen) = '\0'; + logd(LOG_DEBUG, "option82_plugin: an answer from untrusted circuit: %s. Ignored", p); + return 0; + } + need_strip = 0; + } else if (!never_strip_answer) + need_strip = 1; + + /* strip option82 */ + if (need_strip || always_strip_answer) { + opt_size = opt[1] + 2; + memmove(opt, opt + opt_size, *psize - (opt + opt_size - *packet)); + *psize -= opt_size; + udp->uh_ulen = htons(ntohs(udp->uh_ulen) - opt_size); + ip->ip_len = htons(ntohs(ip->ip_len) - opt_size); + ip->ip_sum = 0; + ip->ip_sum = htons(ip_checksum((const char *)ip, sizeof(struct ip))); + } + return 1; } struct plugin_data option82_plugin = { diff --git a/radius_plugin.c b/radius_plugin.c index 9e41029..249cf32 100644 --- a/radius_plugin.c +++ b/radius_plugin.c @@ -1,31 +1,28 @@ -/* - * Copyright (c) 2007-2012 Sergey Matveychuk - * Yandex, LLC. All rights reserved. - * +/* Copyright (c) 2007-2012 Sergey Matveychuk Yandex, LLC. All rights + * reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 4. Neither the name + * of the company nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ + * SUCH DAMAGE. */ #include #include @@ -40,255 +37,248 @@ static struct rad_handle *rh; static char **only_for; -static unsigned only_for_num=0; +static unsigned only_for_num = 0; static struct in_addr bind_addr; static pthread_mutex_t mtx; void * send_acct(void *packet) { - struct dhcp_packet *dhcp = (struct dhcp_packet *)packet; - char buf[100]; - - /* Ignore all packets w/o an assigned IP address */ - if(dhcp->yiaddr.s_addr == 0) { - free(packet); - return NULL; - } - - pthread_mutex_lock(&mtx); - if(rad_create_request(rh, RAD_ACCOUNTING_REQUEST) == -1) { - logd(LOG_ERR, "radius_plugin: rad_create_request()"); - goto end; - } - - if(rad_put_int(rh, RAD_ACCT_STATUS_TYPE, RAD_START) == -1) { - logd(LOG_ERR, "radius_plugin: rad_put_int(RAD_ACCT_STATUS_TYPE) error"); - goto end; - } - - if(rad_put_string(rh, RAD_USER_NAME, print_mac(dhcp->chaddr, buf)) == -1) { - logd(LOG_ERR, "radius_plugin: rad_put_string()"); - goto end; - } + struct dhcp_packet *dhcp = (struct dhcp_packet *)packet; + char buf[100]; - if(rad_put_addr(rh, RAD_FRAMED_IP_ADDRESS, dhcp->yiaddr) == -1) { - logd(LOG_ERR, "radius_plugin: rad_put_addr()"); - goto end; - } - - if(rad_put_int(rh, RAD_NAS_PORT, dhcp->yiaddr.s_addr) == -1) { - logd(LOG_ERR, "radius_plugin: rad_put_int(port)"); - goto end; - } - - if(rad_put_addr(rh, RAD_NAS_IP_ADDRESS, bind_addr) == -1) { - logd(LOG_ERR, "radius_plugin: rad_put_addr()"); - goto end; - } - - if(rad_send_request(rh) == -1) - logd(LOG_ERR, "rad_send_request(): %s", rad_strerror(rh)); - else - logd(LOG_DEBUG, "OK"); + /* Ignore all packets w/o an assigned IP address */ + if (dhcp->yiaddr.s_addr == 0) { + free(packet); + return NULL; + } + pthread_mutex_lock(&mtx); + if (rad_create_request(rh, RAD_ACCOUNTING_REQUEST) == -1) { + logd(LOG_ERR, "radius_plugin: rad_create_request()"); + goto end; + } + if (rad_put_int(rh, RAD_ACCT_STATUS_TYPE, RAD_START) == -1) { + logd(LOG_ERR, "radius_plugin: rad_put_int(RAD_ACCT_STATUS_TYPE) error"); + goto end; + } + if (rad_put_string(rh, RAD_USER_NAME, print_mac(dhcp->chaddr, buf)) == -1) { + logd(LOG_ERR, "radius_plugin: rad_put_string()"); + goto end; + } + if (rad_put_addr(rh, RAD_FRAMED_IP_ADDRESS, dhcp->yiaddr) == -1) { + logd(LOG_ERR, "radius_plugin: rad_put_addr()"); + goto end; + } + if (rad_put_int(rh, RAD_NAS_PORT, dhcp->yiaddr.s_addr) == -1) { + logd(LOG_ERR, "radius_plugin: rad_put_int(port)"); + goto end; + } + if (rad_put_addr(rh, RAD_NAS_IP_ADDRESS, bind_addr) == -1) { + logd(LOG_ERR, "radius_plugin: rad_put_addr()"); + goto end; + } + if (rad_send_request(rh) == -1) + logd(LOG_ERR, "rad_send_request(): %s", rad_strerror(rh)); + else + logd(LOG_DEBUG, "OK"); end: - pthread_mutex_unlock(&mtx); - free(packet); - return NULL; + pthread_mutex_unlock(&mtx); + free(packet); + return NULL; } int radius_plugin_init(plugin_options_head_t *options_head) { - struct plugin_options *opts, *opts_tmp; - char *p, *p1; - int i, n=0, timeout=5, tries=3, dead_time=60; - int servers_num=0, secrets_num=0; - ip_addr_t mask; - char **servers=NULL, **secrets=NULL; + struct plugin_options *opts, *opts_tmp; + char *p, *p1; + int i, n = 0, timeout = 5, tries = 3, dead_time = 60; + int servers_num = 0, secrets_num = 0; + ip_addr_t mask; + char **servers = NULL, **secrets = NULL; - if((rh = rad_acct_open()) == NULL) { - logd(LOG_ERR, "radius_plugin: can't intialize libradius"); - return 0; - } - SLIST_FOREACH_SAFE(opts, options_head, next, opts_tmp) { - if((p = strchr(opts->option_line, '=')) == NULL) { - logd(LOG_ERR, "radius_plugin: syntax error at line: %s", opts->option_line); - return 0; - } - *p = '\0'; p++; - if(strcasecmp(opts->option_line, "servers") == 0) { - servers_num = 0; - for(i=0; ioption_line, '=')) == NULL) { + logd(LOG_ERR, "radius_plugin: syntax error at line: %s", opts->option_line); + return 0; } - logd(LOG_DEBUG, "Server: %s", p1); - strcpy(servers[servers_num], p1); - servers_num++; - } - } else if(strcasecmp(opts->option_line, "secret") == 0) { - secrets_num = 0; - for(i=0; ioption_line, "servers") == 0) { + servers_num = 0; + for (i = 0; i < strlen(p); i++) + if (p[i] == ' ' || p[i] == '\t') + n++; + servers = malloc(sizeof(char *) * (n + 1)); + if (servers == NULL) { + logd(LOG_ERR, "radius_plugin: malloc error"); + return 0; + } + while ((p1 = strsep(&p, " \t")) != NULL) { + servers[servers_num] = malloc(strlen(p1) + 1); + if (servers[servers_num] == NULL) { + logd(LOG_ERR, "radius_plugin: malloc error"); + return 0; + } + logd(LOG_DEBUG, "Server: %s", p1); + strcpy(servers[servers_num], p1); + servers_num++; + } + } else if (strcasecmp(opts->option_line, "secret") == 0) { + secrets_num = 0; + for (i = 0; i < strlen(p); i++) + if (p[i] == ' ' || p[i] == '\t') + n++; + secrets = malloc(sizeof(char *) * (n + 1)); + if (secrets == NULL) { + logd(LOG_ERR, "radius_plugin: malloc error"); + return 0; + } + while ((p1 = strsep(&p, " \t")) != NULL) { + secrets[secrets_num] = malloc(strlen(p1) + 1); + if (secrets[secrets_num] == NULL) { + logd(LOG_ERR, "radius_plugin: malloc error"); + return 0; + } + logd(LOG_DEBUG, "secret: %s", p1); + strcpy(secrets[secrets_num], p1); + secrets_num++; + } + } else if (strcasecmp(opts->option_line, "timeout") == 0) { + timeout = strtol(p, NULL, 10); + if (timeout < 1) { + logd(LOG_ERR, "radius_plugin: timeout error"); + return 0; + } + logd(LOG_DEBUG, "timeout set to: %u", timeout); + } else if (strcasecmp(opts->option_line, "tries") == 0) { + tries = strtol(p, NULL, 10); + if (tries < 1) { + logd(LOG_ERR, "radius_plugin: tries error"); + return 0; + } + logd(LOG_DEBUG, "tries set to: %u", tries); + } else if (strcasecmp(opts->option_line, "dead_time") == 0) { + dead_time = strtol(p, NULL, 10); + if (dead_time == 0 && errno != 0) { + logd(LOG_ERR, "radius_plugin: dead_time error"); + return 0; + } + logd(LOG_DEBUG, "dead_time set to: %d", dead_time); + } else if (strcasecmp(opts->option_line, "bind_to") == 0) { + if (inet_pton(AF_INET, p, &bind_addr.s_addr) != 1) + if (!get_ip(p, &bind_addr.s_addr, &mask)) { + logd(LOG_ERR, "radius_plugin: interface %s not found", p); + return 0; + } + } else if (strcasecmp(opts->option_line, "only_for") == 0) { + only_for_num = 0; + for (i = 0; i < strlen(p); i++) + if (p[i] == ' ' || p[i] == '\t') + n++; + only_for = malloc(sizeof(char *) * (n + 1)); + if (only_for == NULL) { + logd(LOG_ERR, "radius_plugin: malloc error"); + return 0; + } + while ((p1 = strsep(&p, " \t")) != NULL) { + only_for[only_for_num] = malloc(strlen(p1) + 1); + if (only_for[only_for_num] == NULL) { + logd(LOG_ERR, "radius_plugin: malloc error"); + return 0; + } + strcpy(only_for[only_for_num], p1); + only_for_num++; + } + } else { + logd(LOG_ERR, "radius_plugin: unknown option at line: %s", opts->option_line); + return 0; } - logd(LOG_DEBUG, "secret: %s", p1); - strcpy(secrets[secrets_num], p1); - secrets_num++; - } - } else if(strcasecmp(opts->option_line, "timeout") == 0) { - timeout = strtol(p, NULL, 10); - if(timeout < 1) { - logd(LOG_ERR, "radius_plugin: timeout error"); - return 0; - } - logd(LOG_DEBUG, "timeout set to: %u", timeout); - } else if(strcasecmp(opts->option_line, "tries") == 0) { - tries = strtol(p, NULL, 10); - if(tries < 1) { - logd(LOG_ERR, "radius_plugin: tries error"); - return 0; - } - logd(LOG_DEBUG, "tries set to: %u", tries); - } else if(strcasecmp(opts->option_line, "dead_time") == 0) { - dead_time = strtol(p, NULL, 10); - if(dead_time == 0 && errno != 0) { - logd(LOG_ERR, "radius_plugin: dead_time error"); + free(opts->option_line); + SLIST_REMOVE(options_head, opts, plugin_options, next); + free(opts); + } + + if (servers_num == 0) { + logd(LOG_ERR, "radius_plugin: at least one server must be defined"); return 0; - } - logd(LOG_DEBUG, "dead_time set to: %d", dead_time); - } else if(strcasecmp(opts->option_line, "bind_to") == 0) { - if(inet_pton(AF_INET, p, &bind_addr.s_addr) != 1) - if(!get_ip(p, &bind_addr.s_addr, &mask)) { - logd(LOG_ERR, "radius_plugin: interface %s not found", p); - return 0; - } - } else if(strcasecmp(opts->option_line, "only_for") == 0) { - only_for_num = 0; - for(i=0; ioption_line); - return 0; } - free(opts->option_line); - SLIST_REMOVE(options_head, opts, plugin_options, next); - free(opts); - } - - if(servers_num == 0) { - logd(LOG_ERR, "radius_plugin: at least one server must be defined"); - return 0; - } - if(secrets_num == 0) { - logd(LOG_ERR, "radius_plugin: at least one secret must be defined"); - return 0; - } - if(secrets_num > 1 && secrets_num != servers_num) { - logd(LOG_ERR, "radius_plugin: number of secrets must be one or the same as servers number"); - return 0; - } - for(i=0; i 1 && secrets_num != servers_num) { + logd(LOG_ERR, "radius_plugin: number of secrets must be one or the same as servers number"); + return 0; } - for(i=0; iname) == 0) - found=1; + /* Look for interfaces we should do radius request */ + found = 0; + for (i = 0; i < only_for_num; i++) + if (strcmp(only_for[i], intf->name) == 0) + found = 1; - if(only_for_num == 0 || found) { - b = malloc(*psize-(ETHER_HDR_LEN+DHCP_UDP_OVERHEAD)); - if(b == NULL) { - logd(LOG_ERR, "radius_plugin: malloc error"); - return 0; + if (only_for_num == 0 || found) { + b = malloc(*psize - (ETHER_HDR_LEN + DHCP_UDP_OVERHEAD)); + if (b == NULL) { + logd(LOG_ERR, "radius_plugin: malloc error"); + return 0; + } + memcpy(b, *buf + ETHER_HDR_LEN + DHCP_UDP_OVERHEAD, *psize - (ETHER_HDR_LEN + DHCP_UDP_OVERHEAD)); + pthread_create(&tid, NULL, send_acct, b); + pthread_detach(tid); } - memcpy(b, *buf+ETHER_HDR_LEN+DHCP_UDP_OVERHEAD, *psize-(ETHER_HDR_LEN+DHCP_UDP_OVERHEAD)); - pthread_create(&tid, NULL, send_acct, b); - pthread_detach(tid); - } - - return 1; + return 1; } struct plugin_data radius_plugin = { diff --git a/utils.c b/utils.c index 4f48428..e2522be 100644 --- a/utils.c +++ b/utils.c @@ -1,31 +1,28 @@ -/* - * Copyright (c) 2007-2012 Sergey Matveychuk - * Yandex, LLC. All rights reserved. - * +/* Copyright (c) 2007-2012 Sergey Matveychuk Yandex, LLC. All rights + * reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 4. Neither the name + * of the company nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ + * SUCH DAMAGE. */ #include #include @@ -39,74 +36,67 @@ extern unsigned debug; char * print_mac(uint8_t *s, char *buf) { - sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", - s[0],s[1],s[2],s[3],s[4],s[5]); - return buf; + sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", + s[0], s[1], s[2], s[3], s[4], s[5]); + return buf; } char * print_ip(ip_addr_t ip, char *buf) { - union { - ip_addr_t n; - uint8_t b[4]; - } u; + union { + ip_addr_t n; + uint8_t b[4]; + } u; - u.n = ip; - sprintf(buf, "%u.%u.%u.%u", u.b[0], u.b[1], u.b[2], u.b[3]); - return buf; + u.n = ip; + sprintf(buf, "%u.%u.%u.%u", u.b[0], u.b[1], u.b[2], u.b[3]); + return buf; } char * print_xid(uint32_t ip, char *buf) { - union { - uint32_t n; - uint8_t b[4]; - } u; + union { + uint32_t n; + uint8_t b[4]; + } u; - u.n = ip; - sprintf(buf, "0x%02x%02x%02x%02x", u.b[0], u.b[1], u.b[2], u.b[3]); - return buf; + u.n = ip; + sprintf(buf, "0x%02x%02x%02x%02x", u.b[0], u.b[1], u.b[2], u.b[3]); + return buf; } -/* - * Print a log message - */ +/* Print a log message */ void -logd(int log_level, char *fmt, ...) +logd(int log_level, char *fmt,...) { - va_list ap; - char buf[1024]; + va_list ap; + char buf[1024]; - va_start(ap, fmt); + va_start(ap, fmt); - vsprintf(buf, fmt, ap); - if(debug) { - printf(buf); - putchar('\n'); - } else - if(log_level != LOG_DEBUG) - syslog(LOG_ERR, buf); + vsprintf(buf, fmt, ap); + if (debug) { + printf(buf); + putchar('\n'); + } else if (log_level != LOG_DEBUG) + syslog(LOG_ERR, buf); - va_end(ap); + va_end(ap); } -/* - * Rerurn 1(true) for strings "yes", "on", "1" - * or 0(false) for strings "no", "off", "0" - * and -1 for an error. - * All strings is case insensitive. - */ +/* Rerurn 1(true) for strings "yes", "on", "1" or 0(false) for strings "no", + * "off", "0" and -1 for an error. All strings is case insensitive. */ int get_bool_value(const char *str) { - if(strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 || + if (strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 || strcmp(str, "1")) - return 1; - else if(strcasecmp(str, "no") == 0 || strcasecmp(str, "off") == 0 || - strcmp(str, "0")) - return 0; - else - return -1; + return 1; + else if (strcasecmp(str, "no") == 0 || strcasecmp(str, "off") == 0 || + strcmp(str, "0")) + return 0; + else + return -1; }