BEGIN { for(i = 0; i<255; i++) { x2d[sprintf("%02x", i)] = i; x2d[sprintf("%02X", i)] = i; } static["00:0f:21:78:b4:e8"] = "10.253.200.1"; static["00:0f:21:78:b4:ea"] = "10.253.200.2"; static["00:0f:21:78:b4:d4"] = "10.253.200.3"; static["00:0f:21:78:b4:d6"] = "10.253.200.4"; static["00:0c:42:02:1c:fa"] = "10.100.8.19"; static["00:0c:42:02:1c:fb"] = "10.100.8.19"; static["00:0c:42:02:1c:fc"] = "10.100.8.19"; static["00:0c:42:02:1c:fd"] = "10.100.8.19"; static["00:0c:42:03:1a:69"] = "10.100.8.19"; static["00:0c:42:03:1a:6a"] = "10.100.8.19"; } function sql_get(qry) { server="localhost"; db="ncc3"; user="autoboot"; passwd="........."; command = "mysql -u " user " --password='" passwd "' -B -e '" qry "' " db; legend = ""; res = ""; delete q; n = 0; while((command | getline z) > 0) { if(length(legend) == 0) legend = z; else { n++; res = z; } } close(command); n1 = split(legend, la, "\t"); n2 = split(res, ra, "\t"); if(n1 == n2) { for(i = 1; i <= n1; i++) q[la[i]] = ra[i]; } return n; } function do_log(mac, string) { stamp = strftime("%Y-%m-%d %H:%M:%S"); printf "%s [%s] %s\n", stamp, mac, string >>"/var/log/awkdhcpd.log"; } function retrieve_ci(mac) { ip = conf["your address"]; if(substr(ip, 1, 1) == "a") ip = substr(ip, 2); if(sql_get("SELECT ip,prefixlen,dns,gw,inet_ntoa(pow(2, 32) - pow(2, 32 - prefixlen)) as mask FROM list_ip_classes WHERE deleted = 0 AND inet_aton(\"" ip "\") >= first_ip AND inet_aton(\"" ip "\") <= last_ip LIMIT 1")) { conf["dns server"] = "a" q["dns"]; conf["subnet mask"] = "a" q["mask"]; conf["router"] = "a" q["gw"]; do_log(mac, "Class information for " ip ": netmask = " q["mask"] ", dns = " q["dns"] ", gw = " q["gw"]); return 1; } do_log(mac, "Unable to provide class information for " ip); return 0; } function retrieve_config(mac) { delete conf; conf["dns server"] = "a217.173.160.35, 217.173.160.6"; conf["time server"] = "a10.253.100.4"; conf["time offset"] = "i3600"; conf["lease time"] = "i86400"; conf["tftp server"] = "s10.253.100.4"; # Static setups: lowermac = tolower(mac); if(lowermac in static) { ip = static[lowermac]; conf["your address"] = "a" ip; # Custom do_log(mac, "Mapped statically to " ip); if(ip == "10.100.8.19") { conf["router"] = "a10.100.8.1"; conf["subnet mask"] = "a255.255.255.0"; conf["boot filename"] = "simg.elf"; conf["next server"] = "a10.253.100.4"; return 1; } if(substr(ip, 1, 6) == "10.253") { conf["router"] = "a10.253.0.1"; conf["subnet mask"] = "a255.255.0.0"; conf["boot filename"] = "s" ip ".cfg"; conf["next server"] = "a10.253.100.4"; return 1; } return retrieve_ci(mac); } # A cable modem, perhaps? if(sql_get("SELECT ip,id FROM modems WHERE mac LIKE \"" mac "\" AND deleted = 0 LIMIT 1")) { do_log(mac, "Identified as CM #" q["id"]); conf["your address"] = "a" q["ip"]; conf["router"] = "a10.253.0.1"; conf["subnet mask"] = "a255.255.0.0"; conf["boot filename"] = "s" q["ip"] ".cfg"; conf["next server"] = "a10.253.100.4"; return 1; } # Fixed setup? if(sql_get("SELECT allocated_to,ip FROM ip_addresses WHERE mac LIKE \"" mac "\"")) { do_log(mac, "Identified as fixed setup, object#" q["allocated_to"]); conf["your address"] = "a" q["ip"]; sql_get("UPDATE ip_addresses SET last_contact = " systime() " WHERE ip = \"" q["ip"] "\""); return retrieve_ci(mac); } # Learned ? if(sql_get("SELECT allocated_to,ip FROM ip_addresses WHERE learned_mac LIKE \"" mac "\"")) { do_log(mac, "Identified as learned MAC, object#" q["allocated_to"]); conf["your address"] = "a" q["ip"]; sql_get("UPDATE ip_addresses SET last_contact = " systime() " WHERE ip = \"" q["ip"] "\""); return retrieve_ci(mac); } # Relayed by a CMTS? if(vars["relay"] != "a0.0.0.0") { mac_transformed = x2d[substr(mac, 1, 2)] "." x2d[substr(mac, 4, 2)] "." x2d[substr(mac, 7, 2)] "." x2d[substr(mac, 10, 2)] "." x2d[substr(mac, 13, 2)] "." x2d[substr(mac, 16, 2)]; cmd = "/usr/local/bin/braa -t2 -a2 " substr(vars["relay"], 2) ":.1.3.6.1.4.1.482.60.2.16.1.2." mac_transformed; cmd | getline res; close(cmd); n = split(res, a, ":"); if((substr(a[4], 1, 5) != "Error") && length(a[4]) == 17) { modemmac = gensub(" ", ":", "g", a[4]); do_log(mac, "Identified as a CPE behind CM " modemmac); if(sql_get("SELECT ip_addresses.ip AS ip, modems.owner AS id FROM ip_addresses,modems WHERE ip_addresses.allocated_to = modems.owner AND ip_addresses.allocated_to != \"\" AND modems.deleted = 0 AND (ip_addresses.mac = \"*\" OR ip_addresses.mac = \"\") AND ip_addresses.ip NOT LIKE \"10.%\" AND modems.mac LIKE \"" modemmac "\"ORDER BY last_contact LIMIT 1")) { clid = q["id"]; clip = q["ip"]; do_log(mac, "Customer #" clid ", offering IP " clip); conf["your address"] = "a" q["ip"]; sql_get("UPDATE ip_addresses SET last_contact = " systime() ", learned_mac = \"" mac "\" WHERE ip=\"" clip "\""); return retrieve_ci(mac); } else { do_log(mac, "No dynamically allocatable addresses"); return 0; } } } do_log(mac, "Unidentified client"); return 0; } function copyconfig() { for(i in conf) response[i] = conf[i]; } function insert(i) { if(conf[i]) response[i] = conf[i]; } function finish() { for(i in response) print i ": " response[i]; exit; } /^end of message$/ { DHCPDISCOVER="h01"; DHCPOFFER="h02"; DHCPREQUEST="h03"; DHCPDECLINE="h04"; DHCPACK="h05"; DHCPNAK="h06"; DHCPRELEASE="h07"; # We need the MAC mac = substr(vars["client hardware"], 2); if(length(mac) != 17) { do_log(mac, "Parse error in the MAC address"); exit; } if(!retrieve_config(mac)) { do_log(mac, "Unidentified host, ignoring"); exit; } response["transaction id"] = vars["transaction id"]; response["server id"] = "hBADCAFE0"; response["flags"] = vars["flags"]; response["client hardware"] = vars["client hardware"]; response["relay"] = vars["relay"]; if(vars["message type"] == DHCPDISCOVER) { do_log(mac, "DHCPDISCOVER: Sending an offer with current configuration"); response["message type"] = DHCPOFFER; copyconfig(); finish(); } if(vars["message type"] == DHCPREQUEST) { # Check basic parameters valid = 1; response["requested address"] = vars["requested address"]; response["your address"] = conf["your address"]; if(vars["requested address"] != conf["your address"]) { do_log(mac, "Wrong address (" vars["requested address"] ")"); valid = 0; } if(vars["subnet mask"]) { if(vars["subnet mask"] != conf["subnet mask"]) { valid = 0; do_log(mac, "Wrong subnet mask (" vars["subnet mask"] ")"); } } if(vars["router"]) { if(vars["router"] != conf["router"]) { valid = 0; do_log(mac, "Wrong gateway address (" vars["router"] ")"); } } insert("boot filename"); insert("router"); insert("subnet mask"); insert("tftp server"); insert("dns server"); insert("time offset"); insert("lease time"); insert("next server"); if(valid) { do_log(mac, "DHCPREQUEST for " vars["requested address"] ": Acknowledging"); response["message type"] = DHCPACK; ip = substr(vars["requested address"], 2); if(match(ip, "^10\\.253\\.")) { system("touch /home/stats/modem2/recent/" ip); system("/sbin/arp -s " ip " " mac); } } else { do_log(mac, "DHCPREQUEST for " vars["requested address"] ": Declining"); response["message type"] = DHCPNAK; } finish(); } do_log(mac, "Unsupported message type, ignoring"); exit; } /^[A-Za-z0-9 ]+: / { var = gensub(":.*$", "", "g", $0); val = gensub("^[A-Za-z0-9 ]+: *", "", "g", $0); var = gensub("'", "", "g", var); val = gensub("'", "", "g", val); vars[var] = val; }