1/* ----------------------------------------------------------------------- *
2 *
3 *   Copyright 2007 H. Peter Anvin - All Rights Reserved
4 *   Copyright 2011 Timothy J Gleason <timmgleason_at_gmail.com> - All Rights Reserved
5 *
6 *   Permission is hereby granted, free of charge, to any person
7 *   obtaining a copy of this software and associated documentation
8 *   files (the "Software"), to deal in the Software without
9 *   restriction, including without limitation the rights to use,
10 *   copy, modify, merge, publish, distribute, sublicense, and/or
11 *   sell copies of the Software, and to permit persons to whom
12 *   the Software is furnished to do so, subject to the following
13 *   conditions:
14 *
15 *   The above copyright notice and this permission notice shall
16 *   be included in all copies or substantial portions of the Software.
17 *
18 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 *   OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * ----------------------------------------------------------------------- */
28
29/*
30 * dhcp.c
31 *
32 * Adds DHCPINFO functionality to the lua.c32 binary
33 *
34 * gettable() returns a table of the BOOTP message fields returned by
35 * the DHCP server for use in a Lua pxeboot script
36 * See http://tools.ietf.org/html/rfc1542
37 *
38 *	lua key value		RFC key
39 * -----------------------------------------------------------------------
40 *	opcode			op	 message opcode
41 *	hardware.type		htype	 Hardware address type
42 *	hardware.length		hlen	 Hardware address length
43 *	hops			hops	 Used by relay agents
44 *	transaction.id		xid	 transaction id
45 *	elapsed.seconds		secs	 Secs elapsed since client boot
46 *	flags			flags	 DHCP Flags field
47 *	client.ip.addr		ciaddr	 client IP addr
48 *	your.ip.addr		yiaddr	 'Your' IP addr. (from server)
49 *	server.ip.addr		siaddr	 Boot server IP addr
50 *	gateway.ip.addr		giaddr	 Relay agent IP addr
51 *	client.mac		chaddr	 Client hardware addr
52 *	server.hostname		sname	 Optl. boot server hostname
53 * 	boot.file		file	 boot file name (ascii path)
54 *	magic.cookie		cookie	 Magic cookie
55 *
56 * getoptions() returns a table of the DHCP Options field of the BOOTP
57 * message returned by the DHCP server for use in a Lua pxeboot script.
58 * Many of the options are reurned formatted in as strings in a standard,
59 * recognizable format, such as IP addresses.
60 *
61 * 1, 2, and 4 byte numerical options are returned as integers.
62 *
63 * Other Options with non-standard formats are returned as strings of the
64 * raw binary number that was returned by the DHCP server and must be decoded
65 * in a Lua script
66 *
67 * The Options table returns the Option code as the key except where there
68 * are multiple values returned. In those cases, an extra key increment number
69 * is added to allow individual access to each Option value.
70 *
71 *	lua key value		value Name
72 * -----------------------------------------------------------------------
73 *	1			Subnet Mask
74 *	6.1			DNS Server [element 1]
75 *	6.2			DNS Server [element 2]
76 *	6.3			DNS Server [element 3]
77 *	209			PXE Configuration File
78 *	21.1			Policy Filter [element 1]
79 *	21.2			Policy Filter [element 2]
80 *
81 * Options that can have a list of values, but contain only one (like Option 6)
82 * will not return with .sub key values.
83 *
84 * Usage:
85            t = dhcp.gettable()
86
87            for k,v in pairs(t) do
88              print(k.." : "..v)
89            end
90 */
91
92#include <stdio.h>
93#include "dhcp.h"
94#include "lua.h"
95#include "lauxlib.h"
96#include "lualib.h"
97#include <syslinux/pxe.h>
98
99#define STR_BUF_SIZE	129 /* Sized to accomdate File field in BOOTP message */
100
101void
102ip_address_list(lua_State *L, uint8_t* value, uint8_t len, uint8_t option )
103{
104  static char	op_name[64];
105  static char	op_value[255];
106  int		loop;
107
108  loop = len/4;
109
110  if ( loop == 1) {
111    sprintf(op_name, "%u", option);
112    lua_pushstring(L, op_name);
113    sprintf(op_value, "%u.%u.%u.%u", value[0], value[1], value[2], value[3]);
114    lua_pushstring(L, op_value);
115    lua_settable(L,-3);
116  } else {
117      for (int done = 0; done < loop; done++){
118	sprintf(op_name, "%u.%d", option, done+1);
119	lua_pushstring(L, op_name);
120	sprintf(op_value, "%u.%u.%u.%u", value[0+(done*4)], value[1+(done*4)], value[2+(done*4)], value[3+(done*4)]);
121	lua_pushstring(L, op_value);
122	lua_settable(L,-3);
123      }
124  }
125
126}
127
128static int dhcp_getoptions(lua_State *L)
129{
130  void*		dhcpdata = 0;
131  dhcp_t*	dhcp = 0;
132  size_t	dhcplen = 0;
133
134  /* Append the DHCP info */
135  if (pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK,
136    &dhcpdata, &dhcplen))
137  {
138    return 0;
139  }
140
141  dhcp = (dhcp_t*)dhcpdata;
142
143  lua_newtable(L);
144
145  int		done = 0;
146  uint8_t*	ptr = (uint8_t*)&dhcp->options;
147  uint8_t	len;
148  uint8_t	option;
149  uint8_t*	value;
150  static char	op_name[64];
151
152  do {
153      option = *ptr++;
154      len = *ptr++;
155      value = ptr;
156      ptr += len;
157      switch (option) {
158// IP Address formatted lists, including singles
159	case 1:
160	case 3:
161	case 4:
162	case 5:
163	case 6:
164	case 7:
165	case 8:
166	case 9:
167	case 10:
168	case 11:
169	case 16:
170	case 21: /* Policy Filters - address/mask */
171	case 28:
172	case 32:
173	case 33: /* Static routes - destination/router */
174	case 41:
175	case 42:
176	case 44:
177	case 45:
178	case 47:
179	case 48:
180	case 49:
181	case 50:
182	case 51:
183	case 54:
184	case 65:
185	case 68:
186	case 69:
187	case 70:
188	case 71:
189	case 72:
190	case 73:
191	case 74:
192	case 75:
193	case 76:
194	  ip_address_list(L, value, len, option);
195          break;
196// 4byte options - numerical
197        case 2:
198        case 24:
199        case 35:
200        case 38:
201        case 58:
202        case 59:
203        case 211:
204	  sprintf(op_name, "%u", option);
205	  lua_pushstring(L, op_name);
206	  lua_pushinteger(L, ntohl(*(long*)value));
207	  lua_settable(L,-3);
208          break;
209// 2byte options -numerical
210        case 13:
211        case 22:
212        case 26:
213        case 57:
214	  sprintf(op_name, "%u", option);
215	  lua_pushstring(L, op_name);
216	  lua_pushinteger(L, ntohs(*(short*)value));
217	  lua_settable(L,-3);
218          break;
219// 1byte options - numerical
220        case 19:
221        case 20:
222        case 23:
223        case 27:
224        case 29:
225        case 30:
226        case 31:
227        case 34:
228        case 36:
229        case 37:
230        case 39:
231        case 46:
232        case 52:
233        case 53:
234	  sprintf(op_name, "%u", option);
235	  lua_pushstring(L, op_name);
236	  lua_pushinteger(L, *value);
237	  lua_settable(L,-3);
238          break;
239        case 255:
240          done = 1;
241	  break;
242        default:
243	  sprintf(op_name, "%u", option);
244	  lua_pushstring(L, op_name);
245	  lua_pushlstring(L, (const char*)value, len);
246	  lua_settable(L,-3);
247          break;
248      }
249
250    } while (!done);
251
252  return 1;
253}
254
255static int	dhcp_gettable(lua_State *L)
256{
257  void*		dhcpdata = 0;
258  dhcp_t*	dhcp = 0;
259  size_t	dhcplen = 0;
260  static char	dhcp_arg[STR_BUF_SIZE];
261
262  /* Append the DHCP info */
263  if (pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK,
264    &dhcpdata, &dhcplen))
265  {
266    return 0;
267  }
268
269  dhcp = (dhcp_t*)dhcpdata;
270
271
272  lua_newtable(L);
273
274  lua_pushstring(L, "opcode");
275  lua_pushinteger(L, dhcp->op);
276  lua_settable(L,-3);
277
278  lua_pushstring(L, "hardware.type");
279  lua_pushinteger(L, dhcp->htype);
280  lua_settable(L,-3);
281
282  lua_pushstring(L, "hardware.length");
283  lua_pushinteger(L, dhcp->hlen);
284  lua_settable(L,-3);
285
286  lua_pushstring(L, "hops");
287  lua_pushinteger(L, dhcp->hops);
288  lua_settable(L,-3);
289
290  lua_pushstring(L, "transaction.id");
291  lua_pushinteger(L, ntohl(dhcp->xid));
292  lua_settable(L,-3);
293
294  lua_pushstring(L, "elapsed.seconds");
295  lua_pushinteger(L, ntohs(dhcp->secs));
296  lua_settable(L,-3);
297
298  lua_pushstring(L, "flags");
299  lua_pushinteger(L, ntohs(dhcp->flags));
300  lua_settable(L,-3);
301
302  sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->ciaddr[0], dhcp->ciaddr[1], dhcp->ciaddr[2], dhcp->ciaddr[3]);
303  lua_pushstring(L, "client.ip.addr");
304  lua_pushstring(L, dhcp_arg);
305  lua_settable(L,-3);
306
307  sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->yiaddr[0], dhcp->yiaddr[1], dhcp->yiaddr[2], dhcp->yiaddr[3]);
308  lua_pushstring(L, "your.ip.addr");
309  lua_pushstring(L, dhcp_arg);
310  lua_settable(L,-3);
311
312  sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->siaddr[0], dhcp->siaddr[1], dhcp->siaddr[2], dhcp->siaddr[3]);
313  lua_pushstring(L, "server.ip.addr");
314  lua_pushstring(L, dhcp_arg);
315  lua_settable(L,-3);
316
317  sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->giaddr[0], dhcp->giaddr[1], dhcp->giaddr[2], dhcp->giaddr[3]);
318  lua_pushstring(L, "gateway.ip.addr");
319  lua_pushstring(L, dhcp_arg);
320  lua_settable(L,-3);
321
322  sprintf(dhcp_arg, "%02X:%02X:%02X:%02X:%02X:%02X",
323                    dhcp->chaddr[0], dhcp->chaddr[1], dhcp->chaddr[2],
324                    dhcp->chaddr[3], dhcp->chaddr[4], dhcp->chaddr[5]);
325  lua_pushstring(L, "client.mac");
326  lua_pushstring(L, dhcp_arg);
327  lua_settable(L,-3);
328
329  snprintf(dhcp_arg, STR_BUF_SIZE, "%s", dhcp->sname);
330  dhcp_arg[STR_BUF_SIZE-1] = 0; 	/* Guarantee for lua_pushstring that dhcp_arg is 0 terminated /*/
331  lua_pushstring(L, "server.hostname");
332  lua_pushstring(L, dhcp_arg);
333  lua_settable(L,-3);
334
335  snprintf(dhcp_arg, STR_BUF_SIZE, "%s", dhcp->file);
336  dhcp_arg[STR_BUF_SIZE-1] = 0; 	/* Guarantee for lua_pushstring that dhcp_arg is 0 terminated /*/
337  lua_pushstring(L, "boot.file");
338  lua_pushstring(L, dhcp_arg);
339  lua_settable(L,-3);
340
341  sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->cookie[0], dhcp->cookie[1], dhcp->cookie[2], dhcp->cookie[3]);
342  lua_pushstring(L, "magic.cookie");
343  lua_pushstring(L, dhcp_arg);
344  lua_settable(L,-3);
345
346  return 1;
347}
348
349static const luaL_Reg dhcplib[] = {
350  {"gettable", dhcp_gettable},
351  {"getoptions", dhcp_getoptions},
352  {NULL, NULL}
353};
354
355LUALIB_API int luaopen_dhcp (lua_State *L) {
356  luaL_newlib(L, dhcplib);
357  return 1;
358}
359