]> git.vomp.tv Git - vompserver.git/blob - bootpd.c
Merge branch 'master' of ssh://git.vomp.tv:20022/vompserver
[vompserver.git] / bootpd.c
1 /*
2     Copyright 2006 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include <linux/limits.h>
22
23 #include "bootpd.h"
24
25 //void dump(unsigned char* data, USHORT size);
26 //unsigned char dcc(UCHAR c);
27
28 Bootpd::Bootpd()
29 {
30   log = Log::getInstance();
31 }
32
33 Bootpd::~Bootpd()
34 {
35   shutdown();
36 }
37
38 int Bootpd::shutdown()
39 {
40   if (threadIsActive()) threadCancel();
41   ds.shutdown();
42
43   return 1;
44 }
45
46 int Bootpd::run(const char* tconfigDir)
47 {
48   if (threadIsActive()) return 1;
49   log->log("BOOTPD", Log::DEBUG, "Starting bootpd");
50
51   configDir = tconfigDir;
52
53   if (!ds.init(16867))
54   {
55     log->log("BOOTPD", Log::DEBUG, "DSock init error");
56     shutdown();
57     return 0;
58   }
59
60   if (!threadStart())
61   {
62     log->log("BOOTPD", Log::DEBUG, "Thread start error");
63     shutdown();
64     return 0;
65   }
66
67   log->log("BOOTPD", Log::DEBUG, "Bootp replier started");
68   return 1;
69 }
70
71 void Bootpd::threadMethod()
72 {
73   int retval;
74   while(1)
75   {
76     log->log("BOOTPD", Log::DEBUG, "Starting wait");
77     retval = ds.waitforMessage(0);
78     log->log("BOOTPD", Log::DEBUG, "Wait finished");
79
80     if (retval == 0)
81     {
82       log->log("BOOTPD", Log::CRIT, "Wait for packet error");
83       return;
84     }
85     else if (retval == 1)
86     {
87       continue;
88     }
89     else
90     {
91       processRequest((UCHAR*)ds.getData(), ds.getDataLength());
92     }
93   }
94 }
95
96 void Bootpd::processRequest(UCHAR* data, int length)
97 {
98   log->log("BOOTPD", Log::DEBUG, "Got request");
99 //  dump(data, (USHORT)length);
100
101   if (data[0] != 1) return;  // Check it's a request
102
103   // Open a config file for the given MAC
104
105 #ifndef VOMPSTANDALONE
106   const char* useConfigDir = configDir;
107 #else
108   const char* useConfigDir = ".";
109 #endif
110   if (!useConfigDir)
111   {
112     log->log("BOOTPD", Log::ERR, "No config dir!");
113     return;
114   }
115
116   Config config;
117   char configFileName[PATH_MAX];
118   snprintf(configFileName, PATH_MAX, "%s/vomp-%02X-%02X-%02X-%02X-%02X-%02X.conf", useConfigDir, data[28], data[29], data[30], data[31], data[32], data[33]);
119   if (config.init(configFileName))
120   {
121     log->log("BOOTPD", Log::DEBUG, "Opened config file: %s", configFileName);
122   }
123   else
124   {
125     log->log("BOOTPD", Log::ERR, "Could not open/create config file: %s", configFileName);
126     return;
127   }
128
129   // Get an IP for the MVP (make a local copy so future returns don't all have to free string)
130   char newClientIP[100];
131   newClientIP[0] = '\0';
132   bool configHasIP = false;
133   char* cfnewClientIP = config.getValueString("Boot", "IP");
134   if (cfnewClientIP)
135   {
136     strncpy(newClientIP, cfnewClientIP, 99);
137     delete[] cfnewClientIP;
138     configHasIP = true;
139
140     log->log("BOOTPD", Log::DEBUG, "Found IP %s for MVP", newClientIP);
141   }
142   else
143   {
144     log->log("BOOTPD", Log::WARN, "No IP found for MVP. Hopefully it has one already...");
145   }
146
147   // See if we should enforce the IP from the config file
148   int failure;
149   long enforceConfigIP = config.getValueLong("Boot", "Override IP", &failure);
150   if (newClientIP[0] && enforceConfigIP)
151   {
152     log->log("BOOTPD", Log::DEBUG, "Will enforce IP %s on MVP even if it already has another", newClientIP);
153   }
154   else
155   {
156     log->log("BOOTPD", Log::DEBUG, "Will not change MVP IP if it already has one");
157   }
158
159   // See if the MVP already has an IP
160   bool clientAlreadyHasIP = (data[12] || data[13] || data[14] || data[15]);
161
162   /*
163   Subset of Bootp protocol for MVP
164
165   Incoming fields:
166
167   Opcode                    0              Check for value 1            Set to value 2
168   Hardware type             1
169   Hardware address length   2
170   Hop count                 3
171   Transaction ID            4-7
172   Num seconds               8-9
173   Flags                     10-11
174   Client IP                 12-15
175   Your IP                   16-19                                       Set to MVP IP
176   Server IP                 20-23                                       Set to server IP
177   Gateway IP                24-27
178   Client HW address         28-43  (16)    Use to lookup IP for MVP
179   Server Host Name          44-107 (64)
180   Boot filename             108-235 (128)                               Fill with filename for TFTP
181   Vendor info               236-299 (64)
182
183   IP Possibilities
184
185   mvpAlreadyHasIP    configHasIP    enforceConfigIP    result
186 1 Y        0                0                0             discard
187 2 Y        0                0                1             discard
188 3 Y        0                1                0             set config ip
189 4 Y        0                1                1             set config ip
190 5 Y        1                0                0             set mvp ip
191 6 Y        1                0                1             set enforce false, set mvp ip
192 7 Y        1                1                0             set mvp ip
193 8 Y        1                1                1             set config ip
194   */
195
196   if (!clientAlreadyHasIP && !configHasIP) // cases 1 & 2
197   {
198     log->log("BOOTPD", Log::DEBUG, "No IP found to give to MVP");
199     return;
200   }
201
202   if (!configHasIP) enforceConfigIP = 0;             // case 6
203
204   // Ok, we will send a reply
205
206   in_addr_t finalMVPIP;
207
208   if ((!clientAlreadyHasIP) || (configHasIP && enforceConfigIP))
209   {
210     // Cases 3 & 4,              case 8
211     log->log("BOOTPD", Log::DEBUG, "Giving MVP IP from config");
212     // Set config ip
213     *((in_addr_t*)&data[16]) = inet_addr(newClientIP);
214     finalMVPIP = *((in_addr_t*)&data[16]);
215   }
216   else
217   {
218     // Cases 5 & 7
219     // copy existing ciaddr to yiaddr?
220     log->log("BOOTPD", Log::DEBUG, "Leave YI=0 as MVP already has good IP");
221     finalMVPIP = *((in_addr_t*)&data[12]);
222   }
223
224   // Set Server IP in packet
225   if (!getmyip(finalMVPIP, (in_addr_t*)&data[20]))
226   {
227     log->log("BOOTPD", Log::ERR, "Get my IP failed");
228   }
229
230   // Set filename
231   char* tftpFileName = config.getValueString("Boot", "TFTP file name");
232   if (tftpFileName)
233   {
234     strncpy((char*)&data[108], tftpFileName, 127);
235     delete[] tftpFileName;
236   }
237   else
238   {
239     strncpy((char*)&data[108], "vomp-dongle", 127);
240     config.setValueString("Boot", "TFTP file name", "vomp-dongle");
241   }
242
243   // set to reply
244   data[0] = 2;
245
246 //  dump(data, (USHORT)length);
247
248   ds.send("255.255.255.255", 16868, (char*)data, length);
249 }
250
251
252 int Bootpd::getmyip(in_addr_t destination, in_addr_t* result)
253 {
254   int sockfd, r1, r2;
255   struct sockaddr_in my_addr;
256   struct sockaddr_in dest_addr;
257   socklen_t my_addr_len = sizeof(struct sockaddr_in);
258
259   sockfd = socket(AF_INET, SOCK_DGRAM, 0);
260   if (sockfd == -1) return 0;
261
262   dest_addr.sin_family = AF_INET;
263   dest_addr.sin_port = htons(1);
264   dest_addr.sin_addr.s_addr = destination;
265   memset(&(dest_addr.sin_zero), 0, 8);
266
267   r1 = connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
268   if (r1 == -1)
269   {
270     close(sockfd);
271     return 0;
272   }
273
274   memset(&my_addr, 0, sizeof(struct sockaddr_in));
275   r2 = getsockname(sockfd, (struct sockaddr *)&my_addr, &my_addr_len);
276
277   close(sockfd);
278
279   if (r2 == -1) return 0;
280
281   *result = my_addr.sin_addr.s_addr;
282   return 1;
283 }
284
285 /*
286 void dump(unsigned char* data, USHORT size)
287 {
288   printf("Size = %u\n", size);
289
290   USHORT c = 0;
291   while(c < size)
292   {
293     if ((size - c) > 15)
294     {
295       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",
296         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
297         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
298         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]),
299         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]));
300       c += 16;
301     }
302     else
303     {
304       switch (size - c)
305       {
306         case 15:
307           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",
308             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
309             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
310             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]),
311             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]));
312           c += 15;
313           break;
314         case 14:
315           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",
316             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
317             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
318             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]),
319             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
320           c += 14;
321           break;
322         case 13:
323           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",
324             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
325             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
326             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]),
327             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
328           c += 13;
329           break;
330         case 12:
331           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",
332             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
333             data[c+8], data[c+9], data[c+10], data[c+11],
334             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]),
335             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
336           c += 12;
337           break;
338         case 11:
339           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
340             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
341             data[c+8], data[c+9], data[c+10],
342             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]),
343             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
344           c += 11;
345           break;
346         case 10:
347           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
348             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
349             data[c+8], data[c+9],
350             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]),
351             dcc(data[c+8]), dcc(data[c+9]));
352           c += 10;
353           break;
354         case 9:
355           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
356             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
357             data[c+8],
358             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]),
359             dcc(data[c+8]));
360           c += 9;
361           break;
362         case 8:
363           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
364             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
365             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]));
366           c += 8;
367           break;
368         case 7:
369           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
370             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
371             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]));
372           c += 7;
373           break;
374         case 6:
375           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
376             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
377             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
378           c += 6;
379           break;
380         case 5:
381           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
382             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
383             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
384           c += 5;
385           break;
386         case 4:
387           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
388             data[c], data[c+1], data[c+2], data[c+3],
389             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
390           c += 4;
391           break;
392         case 3:
393           printf(" %02X %02X %02X                                            %c%c%c\n",
394             data[c], data[c+1], data[c+2],
395             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
396           c += 3;
397           break;
398         case 2:
399           printf(" %02X %02X                                               %c%c\n",
400             data[c], data[c+1],
401             dcc(data[c]), dcc(data[c+1]));
402           c += 2;
403           break;
404         case 1:
405           printf(" %02X                                                  %c\n",
406             data[c],
407             dcc(data[c]));
408           c += 1;
409           break;
410       }
411     }
412   }
413 }
414
415 unsigned char dcc(UCHAR c)
416 {
417   if (isspace(c)) return ' ';
418   if (isprint(c)) return c;
419   return '.';
420 }
421 */