--- /dev/null
+/*
+ Copyright 2006 Chris Tallon
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "bootpd.h"
+
+//void dump(unsigned char* data, USHORT size);
+//unsigned char dcc(UCHAR c);
+
+Bootpd::Bootpd()
+{
+ log = Log::getInstance();
+}
+
+Bootpd::~Bootpd()
+{
+ shutdown();
+}
+
+int Bootpd::shutdown()
+{
+ if (threadIsActive()) threadCancel();
+ ds.shutdown();
+
+ return 1;
+}
+
+int Bootpd::run()
+{
+ if (threadIsActive()) return 1;
+ log->log("BOOTPD", Log::DEBUG, "Starting bootpd");
+
+ if (!ds.init(16867))
+ {
+ log->log("BOOTPD", Log::DEBUG, "DSock init error");
+ shutdown();
+ return 0;
+ }
+
+ if (!threadStart())
+ {
+ log->log("BOOTPD", Log::DEBUG, "Thread start error");
+ shutdown();
+ return 0;
+ }
+
+ log->log("BOOTPD", Log::DEBUG, "Bootp replier started");
+ return 1;
+}
+
+void Bootpd::threadMethod()
+{
+ int retval;
+ while(1)
+ {
+ log->log("BOOTPD", Log::DEBUG, "Starting wait");
+ retval = ds.waitforMessage(0);
+ log->log("BOOTPD", Log::DEBUG, "Wait finished");
+
+ if (retval == 0)
+ {
+ log->log("BOOTPD", Log::CRIT, "Wait for packet error");
+ return;
+ }
+ else if (retval == 1)
+ {
+ continue;
+ }
+ else
+ {
+ processRequest((UCHAR*)ds.getData(), ds.getDataLength());
+ }
+ }
+}
+
+void Bootpd::processRequest(UCHAR* data, int length)
+{
+ log->log("BOOTPD", Log::DEBUG, "Got request");
+// dump(data, (USHORT)length);
+
+ if (data[0] != 1) return; // Check it's a request
+
+
+ // Open a config file for the given MAC
+
+ const char* configDir = cPlugin::ConfigDirectory();
+// char* configDir = "/opt/dvb/vdr-config-1.3/plugins";
+ if (!configDir)
+ {
+ log->log("BOOTPD", Log::ERR, "No config dir!");
+ return;
+ }
+
+ Config config;
+ char configFileName[PATH_MAX];
+ snprintf(configFileName, PATH_MAX, "%s/vomp-%02X-%02X-%02X-%02X-%02X-%02X.conf", configDir, data[28], data[29], data[30], data[31], data[32], data[33]);
+ if (config.init(configFileName))
+ {
+ log->log("BOOTPD", Log::DEBUG, "Opened config file: %s", configFileName);
+ }
+ else
+ {
+ log->log("BOOTPD", Log::ERR, "Could not open/create config file: %s", configFileName);
+ return;
+ }
+
+ // Get an IP for the MVP (make a local copy so future returns don't all have to free string)
+ char newClientIP[100];
+ newClientIP[0] = '\0';
+ bool configHasIP = false;
+ char* cfnewClientIP = config.getValueString("Boot", "IP");
+ if (cfnewClientIP)
+ {
+ strncpy(newClientIP, cfnewClientIP, 99);
+ delete[] cfnewClientIP;
+ configHasIP = true;
+
+ log->log("BOOTPD", Log::DEBUG, "Found IP %s for MVP", newClientIP);
+ }
+ else
+ {
+ log->log("BOOTPD", Log::WARN, "No IP found for MVP. Hopefully it has one already...");
+ }
+
+ // See if we should enforce the IP from the config file
+ int failure;
+ long enforceConfigIP = config.getValueLong("Boot", "Override IP", &failure);
+ if (newClientIP && enforceConfigIP)
+ {
+ log->log("BOOTPD", Log::DEBUG, "Will enforce IP %s on MVP even if it already has another", newClientIP);
+ }
+ else
+ {
+ log->log("BOOTPD", Log::DEBUG, "Will not change MVP IP if it already has one");
+ }
+
+ // See if the MVP already has an IP
+ bool clientAlreadyHasIP = (data[12] || data[13] || data[14] || data[15]);
+
+ /*
+ Subset of Bootp protocol for MVP
+
+ Incoming fields:
+
+ Opcode 0 Check for value 1 Set to value 2
+ Hardware type 1
+ Hardware address length 2
+ Hop count 3
+ Transaction ID 4-7
+ Num seconds 8-9
+ Flags 10-11
+ Client IP 12-15
+ Your IP 16-19 Set to MVP IP
+ Server IP 20-23 Set to server IP
+ Gateway IP 24-27
+ Client HW address 28-43 (16) Use to lookup IP for MVP
+ Server Host Name 44-107 (64)
+ Boot filename 108-235 (128) Fill with filename for TFTP
+ Vendor info 236-299 (64)
+
+ IP Possibilities
+
+ mvpAlreadyHasIP configHasIP enforceConfigIP result
+1 Y 0 0 0 discard
+2 Y 0 0 1 discard
+3 Y 0 1 0 set config ip
+4 Y 0 1 1 set config ip
+5 Y 1 0 0 set mvp ip
+6 Y 1 0 1 set enforce false, set mvp ip
+7 Y 1 1 0 set mvp ip
+8 Y 1 1 1 set config ip
+ */
+
+ if (!clientAlreadyHasIP && !configHasIP) // cases 1 & 2
+ {
+ log->log("BOOTPD", Log::DEBUG, "No IP found to give to MVP");
+ return;
+ }
+
+ if (!configHasIP) enforceConfigIP = 0; // case 6
+
+ // Ok, we will send a reply
+
+ in_addr_t finalMVPIP;
+
+ if ((!clientAlreadyHasIP) || (configHasIP && enforceConfigIP))
+ {
+ // Cases 3 & 4, case 8
+ log->log("BOOTPD", Log::DEBUG, "Giving MVP IP from config");
+ // Set config ip
+ *((in_addr_t*)&data[16]) = inet_addr(newClientIP);
+ finalMVPIP = *((in_addr_t*)&data[16]);
+ }
+ else
+ {
+ // Cases 5 & 7
+ // copy existing ciaddr to yiaddr?
+ log->log("BOOTPD", Log::DEBUG, "Leave YI=0 as MVP already has good IP");
+ finalMVPIP = *((in_addr_t*)&data[12]);
+ }
+
+ // Set Server IP in packet
+ if (!getmyip(finalMVPIP, (in_addr_t*)&data[20]))
+ {
+ log->log("BOOTPD", Log::ERR, "Get my IP failed");
+ }
+
+ // Set filename
+ strncpy((char*)&data[108], "/mvp/vomp-dongle", 127);
+
+ // set to reply
+ data[0] = 2;
+
+// dump(data, (USHORT)length);
+
+ ds.send("255.255.255.255", 16868, (char*)data, length);
+}
+
+
+int Bootpd::getmyip(in_addr_t destination, in_addr_t* result)
+{
+ int sockfd, r1, r2;
+ struct sockaddr_in my_addr;
+ struct sockaddr_in dest_addr;
+ socklen_t my_addr_len = sizeof(struct sockaddr_in);
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd == -1) return 0;
+
+ dest_addr.sin_family = AF_INET;
+ dest_addr.sin_port = htons(1);
+ dest_addr.sin_addr.s_addr = destination;
+ memset(&(dest_addr.sin_zero), 0, 8);
+
+ r1 = connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
+ if (r1 == -1)
+ {
+ close(sockfd);
+ return 0;
+ }
+
+ memset(&my_addr, 0, sizeof(struct sockaddr_in));
+ r2 = getsockname(sockfd, (struct sockaddr *)&my_addr, &my_addr_len);
+
+ close(sockfd);
+
+ if (r2 == -1) return 0;
+
+ *result = my_addr.sin_addr.s_addr;
+ return 1;
+}
+
+/*
+void dump(unsigned char* data, USHORT size)
+{
+ printf("Size = %u\n", size);
+
+ USHORT c = 0;
+ while(c < size)
+ {
+ if ((size - c) > 15)
+ {
+ printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+ data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
+ dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]), dcc(data[c+15]));
+ c += 16;
+ }
+ else
+ {
+ switch (size - c)
+ {
+ case 15:
+ printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+ data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
+ dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]));
+ c += 15;
+ break;
+ case 14:
+ printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+ data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
+ dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
+ c += 14;
+ break;
+ case 13:
+ printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+ data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
+ dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
+ c += 13;
+ break;
+ case 12:
+ printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+ data[c+8], data[c+9], data[c+10], data[c+11],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
+ dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
+ c += 12;
+ break;
+ case 11:
+ printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+ data[c+8], data[c+9], data[c+10],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
+ dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
+ c += 11;
+ break;
+ case 10:
+ printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+ data[c+8], data[c+9],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
+ dcc(data[c+8]), dcc(data[c+9]));
+ c += 10;
+ break;
+ case 9:
+ printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+ data[c+8],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
+ dcc(data[c+8]));
+ c += 9;
+ break;
+ case 8:
+ printf(" %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]));
+ c += 8;
+ break;
+ case 7:
+ printf(" %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]));
+ c += 7;
+ break;
+ case 6:
+ printf(" %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
+ c += 6;
+ break;
+ case 5:
+ printf(" %02X %02X %02X %02X %02X %c%c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3], data[c+4],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
+ c += 5;
+ break;
+ case 4:
+ printf(" %02X %02X %02X %02X %c%c%c%c\n",
+ data[c], data[c+1], data[c+2], data[c+3],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
+ c += 4;
+ break;
+ case 3:
+ printf(" %02X %02X %02X %c%c%c\n",
+ data[c], data[c+1], data[c+2],
+ dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
+ c += 3;
+ break;
+ case 2:
+ printf(" %02X %02X %c%c\n",
+ data[c], data[c+1],
+ dcc(data[c]), dcc(data[c+1]));
+ c += 2;
+ break;
+ case 1:
+ printf(" %02X %c\n",
+ data[c],
+ dcc(data[c]));
+ c += 1;
+ break;
+ }
+ }
+ }
+}
+
+unsigned char dcc(UCHAR c)
+{
+ if (isspace(c)) return ' ';
+ if (isprint(c)) return c;
+ return '.';
+}
+*/