Annotation of embedaddon/strongswan/src/libimcv/plugins/imc_scanner/imc_scanner.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2011-2015 Andreas Steffen
3: * HSR Hochschule fuer Technik Rapperswil
4: *
5: * This program is free software; you can redistribute it and/or modify it
6: * under the terms of the GNU General Public License as published by the
7: * Free Software Foundation; either version 2 of the License, or (at your
8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9: *
10: * This program is distributed in the hope that it will be useful, but
11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13: * for more details.
14: */
15:
16: #include "imc_scanner_state.h"
17:
18: #include <imc/imc_agent.h>
19: #include <imc/imc_msg.h>
20: #include <ietf/ietf_attr.h>
21: #include <ietf/ietf_attr_attr_request.h>
22: #include <ietf/ietf_attr_port_filter.h>
23:
24: #include <tncif_pa_subtypes.h>
25:
26: #include <pen/pen.h>
27: #include <utils/lexparser.h>
28: #include <utils/debug.h>
29:
30: #include <stdio.h>
31:
32: /* IMC definitions */
33:
34: static const char imc_name[] = "Scanner";
35:
36: static pen_type_t msg_types[] = {
37: { PEN_IETF, PA_SUBTYPE_IETF_FIREWALL }
38: };
39:
40: static imc_agent_t *imc_scanner;
41:
42: /**
43: * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
44: */
45: TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
46: TNC_Version min_version,
47: TNC_Version max_version,
48: TNC_Version *actual_version)
49: {
50: if (imc_scanner)
51: {
52: DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
53: return TNC_RESULT_ALREADY_INITIALIZED;
54: }
55: imc_scanner = imc_agent_create(imc_name, msg_types, countof(msg_types),
56: imc_id, actual_version);
57: if (!imc_scanner)
58: {
59: return TNC_RESULT_FATAL;
60: }
61: if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
62: {
63: DBG1(DBG_IMC, "no common IF-IMC version");
64: return TNC_RESULT_NO_COMMON_VERSION;
65: }
66: return TNC_RESULT_SUCCESS;
67: }
68:
69: /**
70: * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
71: */
72: TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
73: TNC_ConnectionID connection_id,
74: TNC_ConnectionState new_state)
75: {
76: imc_state_t *state;
77:
78: if (!imc_scanner)
79: {
80: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
81: return TNC_RESULT_NOT_INITIALIZED;
82: }
83: switch (new_state)
84: {
85: case TNC_CONNECTION_STATE_CREATE:
86: state = imc_scanner_state_create(connection_id);
87: return imc_scanner->create_state(imc_scanner, state);
88: case TNC_CONNECTION_STATE_DELETE:
89: return imc_scanner->delete_state(imc_scanner, connection_id);
90: default:
91: return imc_scanner->change_state(imc_scanner, connection_id,
92: new_state, NULL);
93: }
94: }
95:
96: /**
97: * Determine all TCP and UDP server sockets listening on physical interfaces
98: */
99: static bool do_netstat(ietf_attr_port_filter_t *attr)
100: {
101: FILE *file;
102: char buf[BUF_LEN];
103: chunk_t line, token;
104: int n = 0;
105: bool success = FALSE;
106: const char system_v4[] = "127.0.1.1";
107: const char loopback_v4[] = "127.0.0.1";
108: const char loopback_v6[] = "::1";
109:
110: /* Open a pipe stream for reading the output of the netstat command */
111: file = popen("/bin/netstat -n -l -p -4 -6 --inet", "r");
112: if (!file)
113: {
114: DBG1(DBG_IMC, "failed to run netstat command");
115: return FALSE;
116: }
117:
118: /* Read the output a line at a time */
119: while (fgets(buf, sizeof(buf), file))
120: {
121: u_char *pos;
122: uint8_t new_protocol, protocol;
123: uint16_t new_port, port;
124: int i;
125: enumerator_t *enumerator;
126: bool allowed, found = FALSE;
127:
128: DBG2(DBG_IMC, "%.*s", (int)(strlen(buf)-1), buf);
129:
130: if (n++ < 2)
131: {
132: /* skip the first two header lines */
133: continue;
134: }
135: line = chunk_create(buf, strlen(buf));
136:
137: /* Extract the IP protocol type */
138: if (!extract_token(&token, ' ', &line))
139: {
140: DBG1(DBG_IMC, "protocol field in netstat output not found");
141: goto end;
142: }
143: if (match("tcp", &token) || match("tcp6", &token))
144: {
145: new_protocol = IPPROTO_TCP;
146: }
147: else if (match("udp", &token) || match("udp6", &token))
148: {
149: new_protocol = IPPROTO_UDP;
150: }
151: else
152: {
153: DBG1(DBG_IMC, "skipped unknown IP protocol in netstat output");
154: continue;
155: }
156:
157: /* Skip the Recv-Q and Send-Q fields */
158: for (i = 0; i < 3; i++)
159: {
160: if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
161: {
162: token = chunk_empty;
163: break;
164: }
165: }
166: if (token.len == 0)
167: {
168: DBG1(DBG_IMC, "local address field in netstat output not found");
169: goto end;
170: }
171:
172: /* Find the local port appended to the local address */
173: pos = token.ptr + token.len;
174: while (*--pos != ':' && --token.len);
175: if (*pos != ':')
176: {
177: DBG1(DBG_IMC, "local port field in netstat output not found");
178: goto end;
179: }
180: token.len--;
181:
182: /* ignore ports of IPv4 and IPv6 loopback interfaces
183: and the internal system IPv4 address */
184: if ((token.len == strlen(system_v4) &&
185: memeq(system_v4, token.ptr, token.len)) ||
186: (token.len == strlen(loopback_v4) &&
187: memeq(loopback_v4, token.ptr, token.len)) ||
188: (token.len == strlen(loopback_v6) &&
189: memeq(loopback_v6, token.ptr, token.len)))
190: {
191: continue;
192: }
193:
194: /* convert the port string to an integer */
195: new_port = atoi(pos+1);
196:
197: /* check if the there is already a port entry */
198: enumerator = attr->create_port_enumerator(attr);
199: while (enumerator->enumerate(enumerator, &allowed, &protocol, &port))
200: {
201: if (new_port == port && new_protocol == protocol)
202: {
203: found = TRUE;
204: }
205: }
206: enumerator->destroy(enumerator);
207:
208: /* Skip the duplicate port entry */
209: if (found)
210: {
211: continue;
212: }
213:
214: /* Add new port entry */
215: attr->add_port(attr, FALSE, new_protocol, new_port);
216: }
217:
218: /* Successfully completed the parsing of the netstat output */
219: success = TRUE;
220:
221: end:
222: /* Close the pipe stream */
223: pclose(file);
224: return success;
225: }
226:
227: /**
228: * Add IETF Port Filter attribute to the send queue
229: */
230: static TNC_Result add_port_filter(imc_msg_t *msg)
231: {
232: pa_tnc_attr_t *attr;
233: ietf_attr_port_filter_t *attr_port_filter;
234:
235: attr = ietf_attr_port_filter_create(pen_type_create(PEN_IETF,
236: IETF_ATTR_PORT_FILTER));
237: attr->set_noskip_flag(attr, TRUE);
238: attr_port_filter = (ietf_attr_port_filter_t*)attr;
239: if (!do_netstat(attr_port_filter))
240: {
241: attr->destroy(attr);
242: return TNC_RESULT_FATAL;
243: }
244: msg->add_attribute(msg, attr);
245:
246: return TNC_RESULT_SUCCESS;
247: }
248:
249: /**
250: * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
251: */
252: TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
253: TNC_ConnectionID connection_id)
254: {
255: imc_state_t *state;
256: imc_msg_t *out_msg;
257: TNC_Result result = TNC_RESULT_SUCCESS;
258:
259: if (!imc_scanner)
260: {
261: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
262: return TNC_RESULT_NOT_INITIALIZED;
263: }
264: if (!imc_scanner->get_state(imc_scanner, connection_id, &state))
265: {
266: return TNC_RESULT_FATAL;
267: }
268: if (lib->settings->get_bool(lib->settings,
269: "%s.plugins.imc-scanner.push_info", TRUE, lib->ns))
270: {
271: out_msg = imc_msg_create(imc_scanner, state, connection_id, imc_id,
272: TNC_IMVID_ANY, msg_types[0]);
273: result = add_port_filter(out_msg);
274: if (result == TNC_RESULT_SUCCESS)
275: {
276: /* send PA-TNC message with the excl flag not set */
277: result = out_msg->send(out_msg, FALSE);
278: }
279: out_msg->destroy(out_msg);
280: }
281:
282: return result;
283: }
284:
285: static TNC_Result receive_message(imc_msg_t *in_msg)
286: {
287: imc_msg_t *out_msg;
288: enumerator_t *enumerator;
289: pa_tnc_attr_t *attr;
290: pen_type_t attr_type;
291: TNC_Result result = TNC_RESULT_SUCCESS;
292: bool fatal_error = FALSE;
293:
294: /* generate an outgoing PA-TNC message - we might need it */
295: out_msg = imc_msg_create_as_reply(in_msg);
296:
297: /* parse received PA-TNC message and handle local and remote errors */
298: result = in_msg->receive(in_msg, out_msg, &fatal_error);
299: if (result != TNC_RESULT_SUCCESS)
300: {
301: out_msg->destroy(out_msg);
302: return result;
303: }
304:
305: /* analyze PA-TNC attributes */
306: enumerator = in_msg->create_attribute_enumerator(in_msg);
307: while (enumerator->enumerate(enumerator, &attr))
308: {
309: attr_type = attr->get_type(attr);
310:
311: if (attr_type.vendor_id != PEN_IETF)
312: {
313: continue;
314: }
315: if (attr_type.type == IETF_ATTR_ATTRIBUTE_REQUEST)
316: {
317: ietf_attr_attr_request_t *attr_cast;
318: pen_type_t *entry;
319: enumerator_t *e;
320:
321: attr_cast = (ietf_attr_attr_request_t*)attr;
322:
323: e = attr_cast->create_enumerator(attr_cast);
324: while (e->enumerate(e, &entry))
325: {
326: if (entry->vendor_id != PEN_IETF)
327: {
328: continue;
329: }
330: switch (entry->type)
331: {
332: case IETF_ATTR_PORT_FILTER:
333: result = add_port_filter(out_msg);
334: break;
335: default:
336: break;
337: }
338: }
339: e->destroy(e);
340: }
341: }
342: enumerator->destroy(enumerator);
343:
344: if (fatal_error)
345: {
346: result = TNC_RESULT_FATAL;
347: }
348: else if (result == TNC_RESULT_SUCCESS)
349: {
350: /* send PA-TNC message with the EXCL flag set */
351: result = out_msg->send(out_msg, TRUE);
352: }
353: out_msg->destroy(out_msg);
354:
355: return result;
356: }
357:
358: /**
359: * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
360:
361: */
362: TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
363: TNC_ConnectionID connection_id,
364: TNC_BufferReference msg,
365: TNC_UInt32 msg_len,
366: TNC_MessageType msg_type)
367: {
368: imc_state_t *state;
369: imc_msg_t *in_msg;
370: TNC_Result result;
371:
372: if (!imc_scanner)
373: {
374: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
375: return TNC_RESULT_NOT_INITIALIZED;
376: }
377: if (!imc_scanner->get_state(imc_scanner, connection_id, &state))
378: {
379: return TNC_RESULT_FATAL;
380: }
381:
382: in_msg = imc_msg_create_from_data(imc_scanner, state, connection_id,
383: msg_type, chunk_create(msg, msg_len));
384: result = receive_message(in_msg);
385: in_msg->destroy(in_msg);
386:
387: return result;
388: }
389:
390: /**
391: * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
392: */
393: TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
394: TNC_ConnectionID connection_id,
395: TNC_UInt32 msg_flags,
396: TNC_BufferReference msg,
397: TNC_UInt32 msg_len,
398: TNC_VendorID msg_vid,
399: TNC_MessageSubtype msg_subtype,
400: TNC_UInt32 src_imv_id,
401: TNC_UInt32 dst_imc_id)
402: {
403: imc_state_t *state;
404: imc_msg_t *in_msg;
405: TNC_Result result;
406:
407: if (!imc_scanner)
408: {
409: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
410: return TNC_RESULT_NOT_INITIALIZED;
411: }
412: if (!imc_scanner->get_state(imc_scanner, connection_id, &state))
413: {
414: return TNC_RESULT_FATAL;
415: }
416: in_msg = imc_msg_create_from_long_data(imc_scanner, state, connection_id,
417: src_imv_id, dst_imc_id, msg_vid, msg_subtype,
418: chunk_create(msg, msg_len));
419: result = receive_message(in_msg);
420: in_msg->destroy(in_msg);
421:
422: return result;
423: }
424:
425: /**
426: * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
427: */
428: TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
429: TNC_ConnectionID connection_id)
430: {
431: if (!imc_scanner)
432: {
433: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
434: return TNC_RESULT_NOT_INITIALIZED;
435: }
436: return TNC_RESULT_SUCCESS;
437: }
438:
439: /**
440: * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
441: */
442: TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
443: {
444: if (!imc_scanner)
445: {
446: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
447: return TNC_RESULT_NOT_INITIALIZED;
448: }
449: imc_scanner->destroy(imc_scanner);
450: imc_scanner = NULL;
451:
452: return TNC_RESULT_SUCCESS;
453: }
454:
455: /**
456: * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
457: */
458: TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
459: TNC_TNCC_BindFunctionPointer bind_function)
460: {
461: if (!imc_scanner)
462: {
463: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
464: return TNC_RESULT_NOT_INITIALIZED;
465: }
466: return imc_scanner->bind_functions(imc_scanner, bind_function);
467: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>