Annotation of embedaddon/strongswan/src/libimcv/plugins/imc_scanner/imc_scanner.c, revision 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>