Пример #1
0
void init_constants(void)
{
	happy(anyaddr(AF_INET, &ipv4_any));
	happy(anyaddr(AF_INET6, &ipv6_any));

	happy(addrtosubnet(&ipv4_any, &ipv4_wildcard));
	happy(addrtosubnet(&ipv6_any, &ipv6_wildcard));

	happy(initsubnet(&ipv4_any, 0, '0', &ipv4_all));
	happy(initsubnet(&ipv6_any, 0, '0', &ipv6_all));
}
Пример #2
0
/* Get a state object.
 * Caller must schedule an event for this object so that it doesn't leak.
 * Caller must insert_state().
 */
struct state *
new_state(void)
{
    static const struct state blank_state;	/* initialized all to zero & NULL */
    static so_serial_t next_so = SOS_FIRST;
    struct state *st;

    st = clone_thing(blank_state, "struct state in new_state()");
    st->st_serialno = next_so++;
    passert(next_so > SOS_FIRST);	/* overflow can't happen! */
    st->st_whack_sock = NULL_FD;

    anyaddr(AF_INET, &st->hidden_variables.st_nat_oa);
    anyaddr(AF_INET, &st->hidden_variables.st_natd);

    DBG(DBG_CONTROL, DBG_log("creating state object #%lu at %p"
			     , st->st_serialno, (void *) st));
    return st;
}
void gcomm::AsioUdpSocket::connect(const gu::URI& uri)
{
    gcomm_assert(state() == S_CLOSED);
    Critical<AsioProtonet> crit(net_);
    asio::ip::udp::resolver resolver(net_.io_service_);

    asio::ip::udp::resolver::query query(unescape_addr(uri.get_host()),
                                   uri.get_port());
    asio::ip::udp::resolver::iterator conn_i(resolver.resolve(query));

    target_ep_ = conn_i->endpoint();

    socket_.open(conn_i->endpoint().protocol());
    socket_.set_option(asio::ip::udp::socket::reuse_address(true));
    socket_.set_option(asio::ip::udp::socket::linger(true, 1));
    set_fd_options(socket_);
    asio::ip::udp::socket::non_blocking_io cmd(true);
    socket_.io_control(cmd);

    const std::string if_addr(
        unescape_addr(
            uri.get_option("socket.if_addr",
                           anyaddr(conn_i->endpoint().address()))));
    asio::ip::address local_if(asio::ip::address::from_string(if_addr));

    if (is_multicast(conn_i->endpoint()) == true)
    {
        join_group(socket_, conn_i->endpoint(), local_if);
        socket_.set_option(
            asio::ip::multicast::enable_loopback(
                gu::from_string<bool>(uri.get_option("socket.if_loop", "false"))));
        socket_.set_option(
            asio::ip::multicast::hops(
                gu::from_string<int>(uri.get_option("socket.mcast_ttl", "1"))));
        socket_.bind(*conn_i);
    }
    else
    {
        socket_.bind(
            asio::ip::udp::endpoint(
                local_if,
                gu::from_string<unsigned short>(uri.get_port())));
    }

    async_receive();
    state_ = S_CONNECTED;
}
Пример #4
0
int
main(int argc, char **argv)
{
/*	int fd; */
	char *endptr;
/*	int ret; */
	int c;
	const char* error_s;

	int error = 0;

	char ipaddr_txt[ADDRTOT_BUF];                
	struct sadb_ext *extensions[K_SADB_EXT_MAX + 1];
	struct sadb_msg *pfkey_msg;
	ip_address pfkey_address_s_ska;
	/*struct sockaddr_in pfkey_address_d_ska;*/
	ip_address pfkey_address_sflow_ska;
	ip_address pfkey_address_dflow_ska;
	ip_address pfkey_address_smask_ska;
	ip_address pfkey_address_dmask_ska;

	int transport_proto = 0;
	int src_port = 0;
	int dst_port = 0;
	ip_said said;
	ip_subnet s_subnet, d_subnet;
 	int eroute_af = 0;
 	int said_af = 0;
	int sa_flags=0;

	int argcount = argc;


	progname = argv[0];

	memset(&pfkey_address_s_ska, 0, sizeof(ip_address));
	memset(&pfkey_address_sflow_ska, 0, sizeof(ip_address));
	memset(&pfkey_address_dflow_ska, 0, sizeof(ip_address));
	memset(&pfkey_address_smask_ska, 0, sizeof(ip_address));
	memset(&pfkey_address_dmask_ska, 0, sizeof(ip_address));
	memset(&said, 0, sizeof(ip_said));
	memset(&s_subnet, 0, sizeof(ip_subnet));
	memset(&d_subnet, 0, sizeof(ip_subnet));

	eroute_af_opt = said_af_opt = edst_opt = spi_opt = proto_opt = said_opt = dst_opt = src_opt = NULL;

	while((c = getopt_long(argc, argv, ""/*"acdD:e:i:hprs:S:f:vl:+:g"*/, longopts, 0)) != EOF) {
		switch(c) {
		case 'g':
			debug = 1;
			pfkey_lib_debug = PF_KEY_DEBUG_PARSE_MAX;
			argcount--;
			break;
		case 'a':
			if(action_type) {
				fprintf(stderr, "%s: Only one of '--add', '--addin', '--replace', '--replacein', '--clear', or '--del' options permitted.\n",
					progname);
				exit(1);
			}
			action_type = EMT_SETEROUTE;
			break;
		case 'A':
			if(action_type) {
				fprintf(stderr, "%s: Only one of '--add', '--addin', '--replace', '--replacein', '--clear', or '--del' options permitted.\n",
					progname);
				exit(1);
			}
			action_type = EMT_INEROUTE;
			break;
		case 'r':
			if(action_type) {
				fprintf(stderr, "%s: Only one of '--add', '--addin', '--replace', '--replacein', '--clear', or '--del' options permitted.\n",
					progname);
				exit(1);
			}
			action_type = EMT_REPLACEROUTE;
			break;
		case 'E':
			if(action_type) {
				fprintf(stderr, "%s: Only one of '--add', '--addin', '--replace', '--replacein', '--clear', or '--del' options permitted.\n",
					progname);
				exit(1);
			}
			action_type = EMT_INREPLACEROUTE;
			break;
		case 'c':
			if(action_type) {
				fprintf(stderr, "%s: Only one of '--add', '--addin', '--replace', '--clear', or '--del' options permitted.\n",
					progname);
				exit(1);
			}
			action_type = EMT_CLREROUTE;
			break;
		case 'd':
			if(action_type) {
				fprintf(stderr, "%s: Only one of '--add', '--addin', '--replace', '--clear', or '--del' options permitted.\n",
					progname);
				exit(1);
			}
			action_type = EMT_DELEROUTE;
			break;
		case 'e':
			if(said_opt) {
				fprintf(stderr, "%s: Error, EDST parameter redefined:%s, already defined in SA:%s\n",
					progname, optarg, said_opt);
				exit (1);
			}				
			if(edst_opt) {
				fprintf(stderr, "%s: Error, EDST parameter redefined:%s, already defined as:%s\n",
					progname, optarg, edst_opt);
				exit (1);
			}				
			error_s = ttoaddr(optarg, 0, said_af, &said.dst);
			if(error_s != NULL) {
				fprintf(stderr, "%s: Error, %s converting --edst argument:%s\n",
					progname, error_s, optarg);
				exit (1);
			}
			edst_opt = optarg;
			break;
		case 'h':
		case '?':
			usage(progname);
			exit(1);
		case 's':
			if(said_opt) {
				fprintf(stderr, "%s: Error, SPI parameter redefined:%s, already defined in SA:%s\n",
					progname, optarg, said_opt);
				exit (1);
			}				
			if(spi_opt) {
				fprintf(stderr, "%s: Error, SPI parameter redefined:%s, already defined as:%s\n",
					progname, optarg, spi_opt);
				exit (1);
			}				
			said.spi = htonl(strtoul(optarg, &endptr, 0));
			if(!(endptr == optarg + strlen(optarg))) {
				fprintf(stderr, "%s: Invalid character in SPI parameter: %s\n",
					progname, optarg);
				exit (1);
			}
			if(ntohl(said.spi) < 0x100) {
				fprintf(stderr, "%s: Illegal reserved spi: %s => 0x%x Must be larger than 0x100.\n",
					progname, optarg, ntohl(said.spi));
				exit(1);
			}
			spi_opt = optarg;
			break;
		case 'p':
			if(said_opt) {
				fprintf(stderr, "%s: Error, PROTO parameter redefined:%s, already defined in SA:%s\n",
					progname, optarg, said_opt);
				exit (1);
			}				
			if(proto_opt) {
				fprintf(stderr, "%s: Error, PROTO parameter redefined:%s, already defined as:%s\n",
					progname, optarg, proto_opt);
				exit (1);
			}
#if 0
			if(said.proto) {
				fprintf(stderr, "%s: Warning, PROTO parameter redefined:%s\n",
					progname, optarg);
				exit (1);
			}
#endif
			if(!strcmp(optarg, "ah"))
				said.proto = SA_AH;
			if(!strcmp(optarg, "esp"))
				said.proto = SA_ESP;
			if(!strcmp(optarg, "tun"))
				said.proto = SA_IPIP;
			if(!strcmp(optarg, "comp"))
				said.proto = SA_COMP;
			if(said.proto == 0) {
				fprintf(stderr, "%s: Invalid PROTO parameter: %s\n",
					progname, optarg);
				exit (1);
			}
			proto_opt = optarg;
			break;
		case 'I':
			if(said_opt) {
				fprintf(stderr, "%s: Error, SAID parameter redefined:%s, already defined in SA:%s\n",
					progname, optarg, said_opt);
				exit (1);
			}				
			if(proto_opt) {
				fprintf(stderr, "%s: Error, PROTO parameter redefined in SA:%s, already defined as:%s\n",
					progname, optarg, proto_opt);
				exit (1);
			}
			if(edst_opt) {
				fprintf(stderr, "%s: Error, EDST parameter redefined in SA:%s, already defined as:%s\n",
					progname, optarg, edst_opt);
				exit (1);
			}
			if(spi_opt) {
				fprintf(stderr, "%s: Error, SPI parameter redefined in SA:%s, already defined as:%s\n",
					progname, optarg, spi_opt);
				exit (1);
			}
			if(said_af_opt) {
				fprintf(stderr, "%s: Error, address family parameter redefined in SA:%s, already defined as:%s\n",
					progname, optarg, said_af_opt);
				exit (1);
			}
			error_s = ttosa(optarg, 0, &said);
			if(error_s != NULL) {
				fprintf(stderr, "%s: Error, %s converting --sa argument:%s\n",
					progname, error_s, optarg);
				exit (1);
			} else if(ntohl(said.spi) < 0x100){
				fprintf(stderr, "%s: Illegal reserved spi: %s => 0x%x Must be larger than or equal to 0x100.\n",
					progname, optarg, said.spi);
				exit(1);
			}
			said_af = addrtypeof(&said.dst);
			said_opt = optarg;
			break;
		case 'v':
			fprintf(stdout, "%s %s\n", me, ipsec_version_code());
			fprintf(stdout, "See `ipsec --copyright' for copyright information.\n");
			exit(1);
		case 'D':
			if(dst_opt) {
				fprintf(stderr, "%s: Error, --dst parameter redefined:%s, already defined as:%s\n",
					progname, optarg, dst_opt);
				exit (1);
			}				
			error_s = ttosubnet(optarg, 0, eroute_af, &d_subnet);
			if (error_s != NULL) {
				fprintf(stderr, "%s: Error, %s converting --dst argument: %s\n",
					progname, error_s, optarg);
				exit (1);
			}
			dst_opt = optarg;
			break;
		case 'S':
			if(src_opt) {
				fprintf(stderr, "%s: Error, --src parameter redefined:%s, already defined as:%s\n",
					progname, optarg, src_opt);
				exit (1);
			}				
			error_s = ttosubnet(optarg, 0, eroute_af, &s_subnet);
			if (error_s != NULL) {
				fprintf(stderr, "%s: Error, %s converting --src argument: %s\n",
					progname, error_s, optarg);
				exit (1);
			}
			src_opt = optarg;
			break;
		case 'P':
			if (transport_proto_opt) {
				fprintf(stderr, "%s: Error, --transport-proto"
					" parameter redefined:%s, "
					"already defined as:%s\n",
					progname, optarg,
					transport_proto_opt);
				exit(1);
			}
			transport_proto_opt = optarg;
			break;
		case 'Q':
			if (src_port_opt) {
				fprintf(stderr, "%s: Error, --src-port"
					" parameter redefined:%s, "
					"already defined as:%s\n",
					progname, optarg, src_port_opt);
				exit(1);
			}
			src_port_opt = optarg;
			break;
		case 'R':
			if (dst_port_opt) {
				fprintf(stderr, "%s: Error, --dst-port"
					" parameter redefined:%s, "
					"already defined as:%s\n",
					progname, optarg, dst_port_opt);
				exit(1);
			}
			dst_port_opt = optarg;
			break;
		case 'l':
			progname = malloc(strlen(argv[0])
					      + 10 /* update this when changing the sprintf() */
					      + strlen(optarg));
			sprintf(progname, "%s --label %s",
				argv[0],
				optarg);
			argcount -= 2;
			break;
		case 'i': /* specifies the address family of the SAID, stored in said_af */
			if(said_af_opt) {
				fprintf(stderr, "%s: Error, address family of SAID redefined:%s, already defined as:%s\n",
					progname, optarg, said_af_opt);
				exit (1);
			}				
			if(!strcmp(optarg, "inet"))
				said_af = AF_INET;
			if(!strcmp(optarg, "inet6"))
				said_af = AF_INET6;
			if(said_af == 0) {
				fprintf(stderr, "%s: Invalid address family parameter for SAID: %s\n",
					progname, optarg);
				exit (1);
			}
			said_af_opt = optarg;
			break;
		case 'f': /* specifies the address family of the eroute, stored in eroute_af */
			if(eroute_af_opt) {
				fprintf(stderr, "%s: Error, address family of eroute redefined:%s, already defined as:%s\n",
					progname, optarg, eroute_af_opt);
				exit (1);
			}				
			if(!strcmp(optarg, "inet"))
				eroute_af = AF_INET;
			if(!strcmp(optarg, "inet6"))
				eroute_af = AF_INET6;
			if(eroute_af == 0) {
				fprintf(stderr, "%s: Invalid address family parameter for eroute: %s\n",
					progname, optarg);
				exit (1);
			}
			eroute_af_opt = optarg;
			break;
		case '+': /* optionsfrom */
			optionsfrom(optarg, &argc, &argv, optind, stderr);
			/* no return on error */
			break;
		default:
			break;
		}
	}

	if(debug) {
		fprintf(stdout, "%s: DEBUG: argc=%d\n", progname, argc);
	}
	
        if(argcount == 1) {
                struct stat sts;
                if ( ((stat ("/proc/net/pfkey", &sts)) == 0) )  {
                         fprintf(stderr, "%s: NETKEY does not support eroute table.\n",progname);

                        exit(1);
                }
                else {
			int ret = 1;
			if ((stat ("/proc/net/ipsec_eroute", &sts)) != 0)  {
				fprintf(stderr, "%s: No eroute table - no IPsec support in kernel (are the modules loaded?)\n", progname);
			} else {
				ret = system("cat /proc/net/ipsec_eroute");
				ret = ret != -1 && WIFEXITED(ret) ? WEXITSTATUS(ret) : 1;
			}
			exit(ret);
                }
        }
	

	/* Sanity checks */

	if(debug) {
		fprintf(stdout, "%s: DEBUG: action_type=%d\n", progname, action_type);
	}

	if (transport_proto_opt != 0) {
	     struct protoent * proto = getprotobyname(transport_proto_opt);
	     if (proto != 0) {
		  transport_proto = proto->p_proto;
	     } else {
		  transport_proto = strtoul(transport_proto_opt, &endptr, 0);
		  if ((*endptr != '\0') 
		      || (transport_proto == 0 && endptr == transport_proto_opt)) {
		       fprintf(stderr, "%s: Invalid character in --transport-proto parameter: %s\n",
			       progname, transport_proto_opt);
		       exit (1);
		  }
		  if (transport_proto > 255) {
		       fprintf(stderr, "%s: --transport-proto parameter: %s must be in the range 0 to 255 inclusive\n",
			       progname, transport_proto_opt);
		       exit (1);
		  }
	     }
	}

        if (src_port_opt != 0 || dst_port_opt != 0) {
		switch (transport_proto) {
		case IPPROTO_UDP:
		case IPPROTO_TCP:
			break;
		default:
			fprintf(stderr, "%s: --transport-proto with either UDP or TCP must be specified if --src-port or --dst-port is used\n", progname);
			exit(1);
		}
        }

	if (src_port_opt) {
	     struct servent * ent = getservbyname(src_port_opt, 0);
	     if (ent != 0) {
		  src_port = ent->s_port;
	     } else {
		  src_port = strtoul(src_port_opt, &endptr, 0);
		  if ((*endptr != '\0')
		      || (src_port == 0 && endptr == src_port_opt)) {
		       fprintf(stderr, "%s: Invalid character in --src-port parameter: %s\n",
			       progname, src_port_opt);
		       exit (1);
		  }
		  if (src_port > 65535) {
		       fprintf(stderr, "%s: --src-port parameter: %s must be in the range 0 to 65535 inclusive\n",
			       progname, src_port_opt);
		  }
		  src_port = htons(src_port);
	     }
	}

	if (dst_port_opt) {
	     struct servent * ent = getservbyname(dst_port_opt, 0);
	     if (ent != 0) {
		  dst_port = ent->s_port;
	     } else {
		  dst_port = strtoul(dst_port_opt, &endptr, 0);
		  if ((*endptr != '\0')
		      || (dst_port == 0 && endptr == dst_port_opt)) {
		       fprintf(stderr, "%s: Invalid character in --dst-port parameter: %s\n",
			       progname, dst_port_opt);
		       exit (1);
		  }
		  if (dst_port > 65535) {
		       fprintf(stderr, "%s: --dst-port parameter: %s must be in the range 0 to 65535 inclusive\n",
			       progname, dst_port_opt);
		  }
		  dst_port = htons(dst_port);
	     }
	}

	switch(action_type) {
	case EMT_SETEROUTE:
	case EMT_REPLACEROUTE:
	case EMT_INEROUTE:
	case EMT_INREPLACEROUTE:
		if(!(said_af_opt && edst_opt && spi_opt && proto_opt) && !(said_opt)) {
			fprintf(stderr, "%s: add and addin options must have SA specified.\n",
				progname);
			exit(1);
		}
	case EMT_DELEROUTE:
		if(!src_opt) {
			fprintf(stderr, "%s: Error -- %s option '--src' is required.\n",
				progname, (action_type == EMT_SETEROUTE) ? "add" : "del");
			exit(1);
		}
		if(!dst_opt) {
			fprintf(stderr, "%s: Error -- %s option '--dst' is required.\n",
				progname, (action_type == EMT_SETEROUTE) ? "add" : "del");
			exit(1);
		}
	case EMT_CLREROUTE:
		break;
	default:
		fprintf(stderr, "%s: exactly one of '--add', '--addin', '--replace', '--del' or '--clear' options must be specified.\n"
			"Try %s --help' for usage information.\n",
			progname, progname);
		exit(1);
	}

	pfkey_sock = pfkey_open_sock_with_error();
	if(pfkey_sock == -1) {
		exit(1);
	}

	if(debug) {
		fprintf(stdout, "%s: DEBUG: PFKEYv2 socket successfully openned=%d.\n", progname, pfkey_sock);
	}

	/* Build an SADB_X_ADDFLOW or SADB_X_DELFLOW message to send down. */
	/* It needs <base, SA, address(SD), flow(SD), mask(SD)> minimum. */
	pfkey_extensions_init(extensions);
	if((error = pfkey_msg_hdr_build(&extensions[0],
					(action_type == EMT_SETEROUTE
					 || action_type == EMT_REPLACEROUTE
					 || action_type == EMT_INREPLACEROUTE
					 || action_type == EMT_INEROUTE)
					? SADB_X_ADDFLOW : SADB_X_DELFLOW,
					proto2satype(said.proto),
					0,
					++pfkey_seq,
					getpid()))) {
		fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
			progname, error);
		pfkey_extensions_free(extensions);
		exit(1);
	}

	if(debug) {
		fprintf(stdout, "%s: DEBUG: pfkey_msg_hdr_build successfull.\n", progname);
	}

	switch(action_type) {
	case EMT_CLREROUTE:
		sa_flags = SADB_X_SAFLAGS_CLEARFLOW;
		goto sa_build;

	case EMT_REPLACEROUTE:
		sa_flags = SADB_X_SAFLAGS_REPLACEFLOW;
		goto sa_build;

	case EMT_INREPLACEROUTE:
		sa_flags = SADB_X_SAFLAGS_REPLACEFLOW | SADB_X_SAFLAGS_INFLOW;
		goto sa_build;

	case EMT_INEROUTE:
		sa_flags = SADB_X_SAFLAGS_INFLOW;
		goto sa_build;

	case EMT_SETEROUTE:
	sa_build:
		if((error = pfkey_sa_build(&extensions[SADB_EXT_SA],
					   SADB_EXT_SA,
					   said.spi, /* in network order */
					   0,
					   0,
					   0,
					   0,
					   sa_flags))) {
			fprintf(stderr, "%s: Trouble building sa extension, error=%d.\n",
				progname, error);
			pfkey_extensions_free(extensions);
			exit(1);
		}
		if(debug) {
			fprintf(stdout, "%s: DEBUG: pfkey_sa_build successful.\n", progname);
		}

	default:
		break;
	}

	switch(action_type) {
	case EMT_SETEROUTE:
	case EMT_REPLACEROUTE:
	case EMT_INEROUTE:
	case EMT_INREPLACEROUTE:
		anyaddr(said_af, &pfkey_address_s_ska);
		if((error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
						SADB_EXT_ADDRESS_SRC,
						0,
						0,
						sockaddrof(&pfkey_address_s_ska)))) {
			addrtot(&pfkey_address_s_ska, 0, ipaddr_txt, sizeof(ipaddr_txt));
			fprintf(stderr, "%s: Trouble building address_s extension (%s), error=%d.\n",
				progname, ipaddr_txt, error);
			pfkey_extensions_free(extensions);
			exit(1);
		}
		if(debug) {
			fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for src.\n", progname);
		}

		if((error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
						SADB_EXT_ADDRESS_DST,
						0,
						0,
						sockaddrof(&said.dst)))) {
			addrtot(&said.dst, 0, ipaddr_txt, sizeof(ipaddr_txt));
			fprintf(stderr, "%s: Trouble building address_d extension (%s), error=%d.\n",
				progname, ipaddr_txt, error);
			pfkey_extensions_free(extensions);
			exit(1);
		}
		if(debug) {
			fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for dst.\n", progname);
		}
	default:
		break;
	}
	
	switch(action_type) {
	case EMT_SETEROUTE:
	case EMT_REPLACEROUTE:
	case EMT_INEROUTE:
	case EMT_INREPLACEROUTE:
	case EMT_DELEROUTE:
		networkof(&s_subnet, &pfkey_address_sflow_ska); /* src flow */
		add_port(eroute_af, &pfkey_address_sflow_ska, src_port);
		if((error = pfkey_address_build(&extensions[SADB_X_EXT_ADDRESS_SRC_FLOW],
						SADB_X_EXT_ADDRESS_SRC_FLOW,
						0,
						0,
						sockaddrof(&pfkey_address_sflow_ska)))) {
			addrtot(&pfkey_address_sflow_ska, 0, ipaddr_txt, sizeof(ipaddr_txt));
			fprintf(stderr, "%s: Trouble building address_sflow extension (%s), error=%d.\n",
				progname, ipaddr_txt, error);
			pfkey_extensions_free(extensions);
			exit(1);
		}
		if(debug) {
			fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for src flow.\n", progname);
		}
	
		networkof(&d_subnet, &pfkey_address_dflow_ska); /* dst flow */
		add_port(eroute_af, &pfkey_address_dflow_ska, dst_port);
		if((error = pfkey_address_build(&extensions[SADB_X_EXT_ADDRESS_DST_FLOW],
						SADB_X_EXT_ADDRESS_DST_FLOW,
						0,
						0,
						sockaddrof(&pfkey_address_dflow_ska)))) {
			addrtot(&pfkey_address_dflow_ska, 0, ipaddr_txt, sizeof(ipaddr_txt));
			fprintf(stderr, "%s: Trouble building address_dflow extension (%s), error=%d.\n",
				progname, ipaddr_txt, error);
			pfkey_extensions_free(extensions);
			exit(1);
		}
		if(debug) {
			fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for dst flow.\n", progname);
		}
		
		maskof(&s_subnet, &pfkey_address_smask_ska); /* src mask */
		add_port(eroute_af, &pfkey_address_smask_ska, src_port ? ~0:0);
		if((error = pfkey_address_build(&extensions[SADB_X_EXT_ADDRESS_SRC_MASK],
						SADB_X_EXT_ADDRESS_SRC_MASK,
						0,
						0,
						sockaddrof(&pfkey_address_smask_ska)))) {
			addrtot(&pfkey_address_smask_ska, 0, ipaddr_txt, sizeof(ipaddr_txt));
			fprintf(stderr, "%s: Trouble building address_smask extension (%s), error=%d.\n",
				progname, ipaddr_txt, error);
			pfkey_extensions_free(extensions);
			exit(1);
		}
		if(debug) {
			fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for src mask.\n", progname);
		}
		
		maskof(&d_subnet, &pfkey_address_dmask_ska); /* dst mask */
		add_port(eroute_af, &pfkey_address_dmask_ska, dst_port ? ~0:0);
		if((error = pfkey_address_build(&extensions[SADB_X_EXT_ADDRESS_DST_MASK],
						SADB_X_EXT_ADDRESS_DST_MASK,
						0,
						0,
						sockaddrof(&pfkey_address_dmask_ska)))) {
			addrtot(&pfkey_address_dmask_ska, 0, ipaddr_txt, sizeof(ipaddr_txt));
			fprintf(stderr, "%s: Trouble building address_dmask extension (%s), error=%d.\n",
				progname, ipaddr_txt, error);
			pfkey_extensions_free(extensions);
			exit(1);
		}
		if(debug) {
			fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for dst mask.\n", progname);
		}
	}
	
	if (transport_proto != 0) {
		if ((error = pfkey_x_protocol_build(&extensions[SADB_X_EXT_PROTOCOL],
						    transport_proto))) {
			fprintf(stderr, "%s: Trouble building transport"
				" protocol extension, error=%d.\n",
				progname, error);
			exit(1);
		}
	}

	if((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN))) {
		fprintf(stderr, "%s: Trouble building pfkey message, error=%d.\n",
			progname, error);
		pfkey_extensions_free(extensions);
		pfkey_msg_free(&pfkey_msg);
		exit(1);
	}
	if(debug) {
		fprintf(stdout, "%s: DEBUG: pfkey_msg_build successful.\n", progname);
	}

	if((error = write(pfkey_sock,
				pfkey_msg,
				pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) !=
	   (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) {
		fprintf(stderr, "%s: pfkey write failed, returning %d with errno=%d.\n",
			progname, error, errno);
		pfkey_extensions_free(extensions);
		pfkey_msg_free(&pfkey_msg);
		switch(errno) {
		case EINVAL:
			fprintf(stderr, "Invalid argument, check kernel log messages for specifics.\n");
			break;
		case ENXIO:
			if((action_type == EMT_SETEROUTE) ||
			   (action_type == EMT_REPLACEROUTE)) {
				fprintf(stderr, "Invalid mask.\n");
				break;
			}
			if(action_type == EMT_DELEROUTE) {
				fprintf(stderr, "Mask not found.\n");
				break;
			}
		case EFAULT:
			if((action_type == EMT_SETEROUTE) ||
			   (action_type == EMT_REPLACEROUTE)) {
				fprintf(stderr, "Invalid address.\n");
				break;
			}
			if(action_type == EMT_DELEROUTE) {
				fprintf(stderr, "Address not found.\n");
				break;
			}
		case EACCES:
			fprintf(stderr, "access denied.  ");
			if(getuid() == 0) {
				fprintf(stderr, "Check permissions.  Should be 600.\n");
			} else {
				fprintf(stderr, "You must be root to open this file.\n");
			}
			break;
		case EUNATCH:
			fprintf(stderr, "KLIPS not loaded.\n");
			break;
		case EBUSY:
			fprintf(stderr, "KLIPS is busy.  Most likely a serious internal error occured in a previous command.  Please report as much detail as possible to development team.\n");
			break;
		case ENODEV:
			fprintf(stderr, "KLIPS not loaded or enabled.\n");
			fprintf(stderr, "No device?!?\n");
			break;
		case ENOBUFS:
			fprintf(stderr, "No kernel memory to allocate SA.\n");
			break;
		case ESOCKTNOSUPPORT:
			fprintf(stderr, "Algorithm support not available in the kernel.  Please compile in support.\n");
			break;
		case EEXIST:
			fprintf(stderr, "eroute already in use.  Delete old one first.\n");
			break;
		case ENOENT:
			if(action_type == EMT_INEROUTE || action_type == EMT_INREPLACEROUTE) {
				fprintf(stderr, "non-existant IPIP SA.\n");
				break;
			}
			fprintf(stderr, "eroute doesn't exist.  Can't delete.\n");
			break;
		case ENOSPC:
			fprintf(stderr, "no room in kernel SAref table.  Cannot process request.\n");
			break;
		case ESPIPE:
			fprintf(stderr, "kernel SAref table internal error.  Cannot process request.\n");
			break;
		default:
			fprintf(stderr, "Unknown socket write error %d.  Please report as much detail as possible to development team.\n", errno);
		}
/*		fprintf(stderr, "%s: socket write returned errno %d\n",
		progname, errno);*/
		exit(1);
	}
	if(debug) {
		fprintf(stdout, "%s: DEBUG: pfkey write successful.\n", progname);
	}

	if(pfkey_msg) {
		pfkey_extensions_free(extensions);
		pfkey_msg_free(&pfkey_msg);
	}

	(void) close(pfkey_sock);  /* close the socket */

	if(debug) {
		fprintf(stdout, "%s: DEBUG: write ok\n", progname);
	}

	exit(0);
}
Пример #5
0
static void default_values(starter_config_t *cfg)
{
	if (cfg == NULL)
		return;

	memset(cfg, 0, sizeof(struct starter_config));

    /* is there enough space for all seen flags? */
	assert(KW_SETUP_LAST - KW_SETUP_FIRST <
		sizeof(cfg->setup.seen) * BITS_PER_BYTE);
	assert(KW_CONN_LAST  - KW_CONN_FIRST <
		sizeof(cfg->conn_default.seen) * BITS_PER_BYTE);
	assert(KW_END_LAST - KW_END_FIRST <
		sizeof(cfg->conn_default.right.seen) * BITS_PER_BYTE);
	assert(KW_CA_LAST - KW_CA_FIRST <
		sizeof(cfg->ca_default.seen) * BITS_PER_BYTE);

	cfg->setup.seen        = LEMPTY;
	cfg->setup.fragicmp    = TRUE;
	cfg->setup.hidetos     = TRUE;
	cfg->setup.uniqueids   = TRUE;
	cfg->setup.interfaces  = new_list("%defaultroute");

#ifdef START_CHARON
	cfg->setup.charonstart = TRUE;
#endif
#ifdef START_PLUTO
	cfg->setup.plutostart  = TRUE;
#endif

	cfg->setup.pluto_ikeport = IKE_UDP_PORT;

	cfg->setup.ha_seqdiff_in  = 0xFFFFFFFF;
	cfg->setup.ha_seqdiff_out = 0xFFFFFFFF;

	cfg->conn_default.seen    = LEMPTY;
	cfg->conn_default.startup = STARTUP_NO;
	cfg->conn_default.state   = STATE_IGNORE;
	cfg->conn_default.policy  = POLICY_ENCRYPT | POLICY_TUNNEL | POLICY_PUBKEY |
								POLICY_PFS | POLICY_MOBIKE;

	cfg->conn_default.ike                   = clone_str(ike_defaults);
	cfg->conn_default.esp                   = clone_str(esp_defaults);
	cfg->conn_default.sa_ike_life_seconds   = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT;
	cfg->conn_default.sa_ipsec_life_seconds = PLUTO_SA_LIFE_DURATION_DEFAULT;
	cfg->conn_default.sa_rekey_margin       = SA_REPLACEMENT_MARGIN_DEFAULT;
	cfg->conn_default.sa_rekey_fuzz         = SA_REPLACEMENT_FUZZ_DEFAULT;
	cfg->conn_default.sa_keying_tries       = SA_REPLACEMENT_RETRIES_DEFAULT;
	cfg->conn_default.addr_family           = AF_INET;
	cfg->conn_default.tunnel_addr_family    = AF_INET;
	cfg->conn_default.xfrm_flags            = 0;
	cfg->conn_default.install_policy	= TRUE;
	cfg->conn_default.dev			= 0;
	cfg->conn_default.dpd_delay		=  30; /* seconds */
	cfg->conn_default.dpd_timeout		= 150; /* seconds */

	cfg->conn_default.left.seen  = LEMPTY;
	cfg->conn_default.right.seen = LEMPTY;

	cfg->conn_default.left.sendcert  = CERT_SEND_IF_ASKED;
	cfg->conn_default.right.sendcert = CERT_SEND_IF_ASKED;

	anyaddr(AF_INET, &cfg->conn_default.left.addr);
	anyaddr(AF_INET, &cfg->conn_default.left.nexthop);
	anyaddr(AF_INET, &cfg->conn_default.right.addr);
	anyaddr(AF_INET, &cfg->conn_default.right.nexthop);
	cfg->conn_default.left.ikeport = 500;
	cfg->conn_default.right.ikeport = 500;

	cfg->ca_default.seen = LEMPTY;
}
Пример #6
0
static void kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token,
				   kw_list_t *kw, char *conn_name, starter_config_t *cfg)
{
	err_t ugh = NULL;
	bool assigned = FALSE;
	bool has_port_wildcard;        /* set if port is %any */

	char *name  = kw->entry->name;
	char *value = kw->value;

	if (!assign_arg(token, KW_END_FIRST, kw, (char *)end, &assigned))
		goto err;

	/* post processing of some keywords that were assigned automatically */
	switch (token)
	{
	case KW_SUBNET:
		if ((strlen(value) >= 6 && strncmp(value,"vhost:",6) == 0)
		||  (strlen(value) >= 5 && strncmp(value,"vnet:",5) == 0))
		{
			/* used by pluto only */
			end->has_virt = TRUE;
		}
		else
		{
			ip_subnet net;
			char *pos;
			int len = 0;

			end->has_client = TRUE;
			conn->tunnel_addr_family = ip_version(value);

			pos = strchr(value, ',');
			if (pos)
			{
				len = pos - value;
			}
			ugh = ttosubnet(value, len, ip_version(value), &net);
			if (ugh != NULL)
			{
				plog("# bad subnet: %s=%s [%s]", name, value, ugh);
				goto err;
			}
		}
		break;
	case KW_SOURCEIP:
		if (end->has_natip)
		{
			plog("# natip and sourceip cannot be defined at the same time");
			goto err;
		}
		if (value[0] == '%')
		{
			if (streq(value, "%modeconfig") || streq(value, "%modecfg") ||
				streq(value, "%config") || streq(value, "%cfg"))
			{
				/* request ip via config payload */
				free(end->sourceip);
				end->sourceip = NULL;
				end->sourceip_mask = 1;
			}
			else
			{	/* %poolname, strip %, serve ip requests */
				free(end->sourceip);
				end->sourceip = clone_str(value+1);
				end->sourceip_mask = 0;
			}
			end->modecfg = TRUE;
		}
		else
		{
			char *pos;
			ip_address addr;
			ip_subnet net;

			conn->tunnel_addr_family = ip_version(value);
			pos = strchr(value, '/');

			if (pos)
			{	/* CIDR notation, address pool */
				ugh = ttosubnet(value, 0, conn->tunnel_addr_family, &net);
				if (ugh != NULL)
				{
					plog("# bad subnet: %s=%s [%s]", name, value, ugh);
					goto err;
				 }
				*pos = '\0';
				free(end->sourceip);
				end->sourceip = clone_str(value);
				end->sourceip_mask = atoi(pos + 1);
			}
			else
			{	/* fixed srcip */
				ugh = ttoaddr(value, 0, conn->tunnel_addr_family, &addr);
				if (ugh != NULL)
				{
					plog("# bad addr: %s=%s [%s]", name, value, ugh);
					goto err;
				}
				end->sourceip_mask = (conn->tunnel_addr_family == AF_INET) ?
									  32 : 128;
			}
		}
		conn->policy |= POLICY_TUNNEL;
		break;
	case KW_SENDCERT:
		if (end->sendcert == CERT_YES_SEND)
		{
			end->sendcert = CERT_ALWAYS_SEND;
		}
		else if (end->sendcert == CERT_NO_SEND)
		{
			end->sendcert = CERT_NEVER_SEND;
		}
		break;
	default:
		break;
	}

	if (assigned)
		return;

	/* individual processing of keywords that were not assigned automatically */
	switch (token)
	{
	case KW_HOST:
		if (streq(value, "%defaultroute"))
		{
			if (cfg->defaultroute.defined)
			{
				end->addr    = cfg->defaultroute.addr;
				end->nexthop = cfg->defaultroute.nexthop;
			}
			else if (!cfg->defaultroute.supported)
			{
				plog("%%defaultroute not supported, fallback to %%any");
			}
			else
			{
				plog("# default route not known: %s=%s", name, value);
				goto err;
			}
		}
		else if (streq(value, "%any") || streq(value, "%any4"))
		{
			anyaddr(conn->addr_family, &end->addr);
		}
		else if (streq(value, "%any6"))
		{
			conn->addr_family = AF_INET6;
			anyaddr(conn->addr_family, &end->addr);
		}
		else if (streq(value, "%group"))
		{
			ip_address any;

			conn->policy |= POLICY_GROUP | POLICY_TUNNEL;
			anyaddr(conn->addr_family, &end->addr);
			anyaddr(conn->tunnel_addr_family, &any);
			end->has_client = TRUE;
		}
		else
		{
			/* check for allow_any prefix */
			if (value[0] == '%')
			{
				end->allow_any = TRUE;
				value++;
			}
			conn->addr_family = ip_version(value);
			ugh = ttoaddr(value, 0, conn->addr_family, &end->addr);
			if (ugh != NULL)
			{
				plog("# bad addr: %s=%s [%s]", name, value, ugh);
				if (streq(ugh, "does not look numeric and name lookup failed"))
				{
					end->dns_failed = TRUE;
					anyaddr(conn->addr_family, &end->addr);
				}
				else
				{
					goto err;
				}
			}
		}
		break;
	case KW_NEXTHOP:
		if (streq(value, "%defaultroute"))
		{
			if (cfg->defaultroute.defined)
			{
				end->nexthop = cfg->defaultroute.nexthop;
			}
			else
			{
				plog("# default route not known: %s=%s", name, value);
				goto err;
			}
		}
		else if (streq(value, "%direct"))
		{
			ugh = anyaddr(conn->addr_family, &end->nexthop);
		}
		else
		{
			conn->addr_family = ip_version(value);
			ugh = ttoaddr(value, 0, conn->addr_family, &end->nexthop);
		}
		if (ugh != NULL)
		{
			plog("# bad addr: %s=%s [%s]", name, value, ugh);
			goto err;
		}
		break;
	case KW_SUBNETWITHIN:
	{
		ip_subnet net;

		end->has_client = TRUE;
		end->has_client_wildcard = TRUE;
		conn->tunnel_addr_family = ip_version(value);

		ugh = ttosubnet(value, 0, ip_version(value), &net);
		if (ugh != NULL)
		{
			plog("# bad subnet: %s=%s [%s]", name, value, ugh);
			goto err;
		}
		end->subnet = clone_str(value);
		break;
	}
	case KW_PROTOPORT:
		ugh = ttoprotoport(value, 0, &end->protocol, &end->port, &has_port_wildcard);
		end->has_port_wildcard = has_port_wildcard;
		break;
	case KW_NATIP:
		if (end->sourceip)
		{
			plog("# natip and sourceip cannot be defined at the same time");
			goto err;
		}
		if (streq(value, "%defaultroute"))
		{
			char buf[64];

			if (cfg->defaultroute.defined)
			{
				addrtot(&cfg->defaultroute.addr, 0, buf, sizeof(buf));
				end->sourceip = clone_str(buf);
			}
			else
			{
				plog("# default route not known: %s=%s", name, value);
				goto err;
			}
		}
		else
		{
			ip_address addr;

			conn->tunnel_addr_family = ip_version(value);
			ugh = ttoaddr(value, 0, conn->tunnel_addr_family, &addr);
			if (ugh != NULL)
			{
				plog("# bad addr: %s=%s [%s]", name, value, ugh);
				goto err;
			}
			end->sourceip = clone_str(value);
		}
		end->has_natip = TRUE;
		conn->policy |= POLICY_TUNNEL;
		break;
	default:
		break;
	}
	return;

err:
	plog("  bad argument value in conn '%s'", conn_name);
	cfg->err++;
}
Пример #7
0
/**
 * Set up hardcoded defaults, from data in programs/pluto/constants.h
 *
 * @param cfg starter_config struct
 * @return void
 */
void ipsecconf_default_values(struct starter_config *cfg)
{
	zero(cfg);	/* ??? pointer fields might not be NULLed */

	TAILQ_INIT(&cfg->conns);

	/* config setup */
	cfg->setup.options[KBF_FRAGICMP] = FALSE; /* see sysctl_ipsec_icmp in ipsec_proc.c */
	cfg->setup.options[KBF_HIDETOS]  = TRUE;
	cfg->setup.options[KBF_PLUTORESTARTONCRASH]  = TRUE;
	cfg->setup.options[KBF_PLUTOSTDERRLOGTIME]  = TRUE;
	cfg->setup.options[KBF_PLUTOSTDERRLOGAPPEND]  = TRUE;
	cfg->setup.options[KBF_UNIQUEIDS] = TRUE;
	cfg->setup.options[KBF_PERPEERLOG] = FALSE;
	cfg->setup.options[KBF_IKEPORT] = IKE_UDP_PORT;
	cfg->setup.options[KBF_NFLOG_ALL] = 0; /* disabled per default */
	cfg->setup.options[KBF_XFRMLIFETIME] = 300; /* not used by pluto itself */
	cfg->setup.options[KBF_NHELPERS] = -1; /* see also plutomain.c */

	cfg->setup.options[KBF_KEEPALIVE] = 0;                  /* config setup */
	cfg->setup.options[KBF_NATIKEPORT] = NAT_IKE_UDP_PORT;
	cfg->setup.options[KBF_DDOS_IKE_TRESHOLD] = DEFAULT_IKE_SA_DDOS_TRESHOLD;
	cfg->setup.options[KBF_MAX_HALFOPEN_IKE] = DEFAULT_MAXIMUM_HALFOPEN_IKE_SA;
	cfg->setup.options[KBF_SHUNTLIFETIME] = PLUTO_SHUNT_LIFE_DURATION_DEFAULT;
	/* Don't inflict BSI requirements on everyone */
	cfg->setup.options[KBF_SEEDBITS] = 0;

#ifdef HAVE_LABELED_IPSEC
	cfg->setup.options[KBF_SECCTX] = SECCTX;
#endif
	cfg->setup.options[KBF_DDOS_MODE] = DDOS_AUTO;

	/* conn %default */
	cfg->conn_default.options[KBF_NAT_KEEPALIVE] = TRUE;    /* per conn */
	cfg->conn_default.options[KBF_TYPE] = KS_TUNNEL;

	cfg->conn_default.options[KBF_INITIAL_CONTACT] = FALSE;
	cfg->conn_default.options[KBF_CISCO_UNITY] = FALSE;
	cfg->conn_default.options[KBF_SEND_VENDORID] = FALSE;

	cfg->conn_default.options[KBF_REMOTEPEERTYPE] = NON_CISCO;

	cfg->conn_default.options[KBF_SHA2_TRUNCBUG] = FALSE;

	cfg->conn_default.options[KBF_IKEPAD] = TRUE;

	cfg->conn_default.options[KBF_IKEV1_NATT] = natt_both;

	/* Network Manager support */
#ifdef HAVE_NM
	cfg->conn_default.options[KBF_NMCONFIGURED] = FALSE;
#endif

#ifdef HAVE_LABELED_IPSEC
	cfg->conn_default.options[KBF_LABELED_IPSEC] = FALSE;
#endif

	cfg->conn_default.options[KBF_XAUTHBY] = XAUTHBY_FILE;
	cfg->conn_default.options[KBF_XAUTHFAIL] = XAUTHFAIL_HARD;

	cfg->conn_default.policy = POLICY_RSASIG | POLICY_TUNNEL |
				   POLICY_ENCRYPT | POLICY_PFS;
	cfg->conn_default.policy |= POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW;	/* ikev2=permit */
	cfg->conn_default.policy |= POLICY_SAREF_TRACK;         /* sareftrack=yes */
	cfg->conn_default.policy |= POLICY_IKE_FRAG_ALLOW;      /* ike_frag=yes */

	cfg->conn_default.options[KBF_IKELIFETIME] =
		OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT;

	cfg->conn_default.options[KBF_RETRANSMIT_TIMEOUT] = RETRANSMIT_TIMEOUT_DEFAULT;
	cfg->conn_default.options[KBF_RETRANSMIT_INTERVAL] = RETRANSMIT_INTERVAL_DEFAULT;

	cfg->conn_default.options[KBF_SALIFETIME]  = SA_LIFE_DURATION_DEFAULT;
	cfg->conn_default.options[KBF_REKEYMARGIN] =
		SA_REPLACEMENT_MARGIN_DEFAULT;
	cfg->conn_default.options[KBF_REKEYFUZZ]   =
		SA_REPLACEMENT_FUZZ_DEFAULT;
	cfg->conn_default.options[KBF_KEYINGTRIES] =
		SA_REPLACEMENT_RETRIES_DEFAULT;

	/* now here is a sticker.. we want it on. But pluto has to be smarter first */
	cfg->conn_default.options[KBF_OPPOENCRYPT] = FALSE;

	cfg->conn_default.options[KBF_CONNADDRFAMILY] = AF_INET;

	cfg->conn_default.left.addr_family = AF_INET;
	anyaddr(AF_INET, &cfg->conn_default.left.addr);
	cfg->conn_default.left.nexttype  = KH_NOTSET;
	anyaddr(AF_INET, &cfg->conn_default.left.nexthop);

	cfg->conn_default.right.addr_family = AF_INET;
	anyaddr(AF_INET, &cfg->conn_default.right.addr);
	cfg->conn_default.right.nexttype = KH_NOTSET;
	anyaddr(AF_INET, &cfg->conn_default.right.nexthop);

	/* default is NOT to look in DNS */
	cfg->conn_default.left.key_from_DNS_on_demand = FALSE;
	cfg->conn_default.right.key_from_DNS_on_demand = FALSE;

	cfg->conn_default.options[KBF_AUTO] = STARTUP_IGNORE;
	cfg->conn_default.state = STATE_LOADED;

	cfg->ctlbase = clone_str(CTL_FILE, "default base");
}
Пример #8
0
static bool validate_end(struct ub_ctx *dnsctx ,
#endif
			struct starter_conn *conn_st,
			struct starter_end *end,
			const char *leftright,
			bool resolvip UNUSED,
			err_t *perr)
{
	err_t er = NULL;
	char *err_str = NULL;
	int family = conn_st->options[KBF_CONNADDRFAMILY];
	bool err = FALSE;

#  define ERR_FOUND(...) { err |= error_append(&err_str, __VA_ARGS__); }

	if (!end->options_set[KNCF_IP])
		conn_st->state = STATE_INCOMPLETE;

	end->addrtype = end->options[KNCF_IP];
	end->addr_family = family;

	/* validate the KSCF_IP/KNCF_IP */
	switch (end->addrtype) {
	case KH_ANY:
		anyaddr(family, &(end->addr));
		break;

	case KH_IFACE:
		/* generally, this doesn't show up at this stage */
		starter_log(LOG_LEVEL_DEBUG, "starter: %s is KH_IFACE", leftright);
		break;

	case KH_IPADDR:
		assert(end->strings[KSCF_IP] != NULL);

		if (end->strings[KSCF_IP][0] == '%') {
			pfree(end->iface);
			end->iface = clone_str(end->strings[KSCF_IP] + 1, "KH_IPADDR end->iface");
			if (!starter_iface_find(end->iface, family,
					       &end->addr,
					       &end->nexthop))
				conn_st->state = STATE_INVALID;
			/* not numeric, so set the type to the iface type */
			end->addrtype = KH_IFACE;
			break;
		}

		er = ttoaddr_num(end->strings[KNCF_IP], 0, family,
				    &(end->addr));
		if (er != NULL) {
			/* not numeric, so set the type to the string type */
			end->addrtype = KH_IPHOSTNAME;
		}

		if (end->id == NULL) {
			ipstr_buf b;

			end->id = clone_str(ipstr(&end->addr, &b), "end if");
		}
		break;

	case KH_OPPO:
		conn_st->policy |= POLICY_OPPORTUNISTIC;
		break;

	case KH_OPPOGROUP:
		conn_st->policy |= POLICY_OPPORTUNISTIC | POLICY_GROUP;
		break;

	case KH_GROUP:
		conn_st->policy |= POLICY_GROUP;
		break;

	case KH_IPHOSTNAME:
		/* generally, this doesn't show up at this stage */
		starter_log(LOG_LEVEL_DEBUG,
			    "starter: %s is KH_IPHOSTNAME", leftright);
		break;

	case KH_DEFAULTROUTE:
		starter_log(LOG_LEVEL_DEBUG,
			    "starter: %s is KH_DEFAULTROUTE", leftright);
		break;

	case KH_NOTSET:
		starter_log(LOG_LEVEL_DEBUG, "starter: %s is KH_NOTSET", leftright);
		break;
	}

	/* validate the KSCF_SUBNET */
	if (end->strings_set[KSCF_SUBNET]) {
		char *value = end->strings[KSCF_SUBNET];

		if (end->strings_set[KSCF_ADDRESSPOOL]) {
			ERR_FOUND("cannot specify both %ssubnet= and %saddresspool=", leftright,
				leftright);
		}

		if (startswith(value, "vhost:") || startswith(value, "vnet:")) {
			er = NULL;
			end->virt = clone_str(value, "validate_end item");
		} else {
			end->has_client = TRUE;
			er = ttosubnet(value, 0, family, &(end->subnet));
		}
		if (er != NULL)
			ERR_FOUND("bad subnet %ssubnet=%s [%s]", leftright,
				  value, er);
	}

	/* set nexthop address to something consistent, by default */
	anyaddr(family, &end->nexthop);
	anyaddr(addrtypeof(&end->addr), &end->nexthop);

	/* validate the KSCF_NEXTHOP */
	if (end->strings_set[KSCF_NEXTHOP]) {
		char *value = end->strings[KSCF_NEXTHOP];

		if (strcaseeq(value, "%defaultroute")) {
			end->nexttype = KH_DEFAULTROUTE;
		} else {
			if (tnatoaddr(value, strlen(value), AF_INET,
				      &(end->nexthop)) != NULL &&
			    tnatoaddr(value, strlen(value), AF_INET6,
				      &(end->nexthop)) != NULL) {
#ifdef DNSSEC
				starter_log(LOG_LEVEL_DEBUG,
					    "Calling unbound_resolve() for %snexthop value",
					    leftright);
				if (!unbound_resolve(dnsctx, value,
						strlen(value), AF_INET,
						&(end->nexthop)) &&
				    !unbound_resolve(dnsctx, value,
						strlen(value), AF_INET6,
						&(end->nexthop)))
					ERR_FOUND("bad value for %snexthop=%s\n",
						leftright, value);
#else
				er = ttoaddr(value, 0, family,
						&(end->nexthop));
				if (er != NULL)
					ERR_FOUND("bad value for %snexthop=%s [%s]",
						leftright, value,
						er);
#endif
			}
			end->nexttype = KH_IPADDR;
		}
	} else {
#if 0
		if (conn_st->policy & POLICY_OPPORTUNISTIC)
			end->nexttype = KH_DEFAULTROUTE;
#endif
		anyaddr(family, &end->nexthop);

		if (end->addrtype == KH_DEFAULTROUTE) {
			end->nexttype = KH_DEFAULTROUTE;
		}
	}

	/* validate the KSCF_ID */
	if (end->strings_set[KSCF_ID]) {
		char *value = end->strings[KSCF_ID];

		pfreeany(end->id);
		end->id = clone_str(value, "end->id");
	}

	if (end->options_set[KSCF_RSAKEY1]) {
		end->rsakey1_type = end->options[KSCF_RSAKEY1];
		end->rsakey2_type = end->options[KSCF_RSAKEY2];

		switch (end->options[KSCF_RSAKEY1]) {
		case PUBKEY_DNS:
		case PUBKEY_DNSONDEMAND:
			end->key_from_DNS_on_demand = TRUE;
			break;

		default:
			end->key_from_DNS_on_demand = FALSE;
			/* validate the KSCF_RSAKEY1/RSAKEY2 */
			if (end->strings[KSCF_RSAKEY1] != NULL) {
				char *value = end->strings[KSCF_RSAKEY1];

				pfreeany(end->rsakey1);
				end->rsakey1 = (unsigned char *)clone_str(value,"end->rsakey1");
			}
			if (end->strings[KSCF_RSAKEY2] != NULL) {
				char *value = end->strings[KSCF_RSAKEY2];

				pfreeany(end->rsakey2);
				end->rsakey2 = (unsigned char *)clone_str(value,"end->rsakey2");
			}
		}
	}

	/* validate the KSCF_SOURCEIP, if any, and if set,
	 * set the subnet to same value, if not set.
	 */
	if (end->strings_set[KSCF_SOURCEIP]) {
		char *value = end->strings[KSCF_SOURCEIP];

		if (tnatoaddr(value, strlen(value), AF_INET,
			      &(end->sourceip)) != NULL &&
		    tnatoaddr(value, strlen(value), AF_INET6,
			      &(end->sourceip)) != NULL) {
#ifdef DNSSEC
			starter_log(LOG_LEVEL_DEBUG,
				    "Calling unbound_resolve() for %ssourceip value",
				    leftright);
			if (!unbound_resolve(dnsctx, value,
					strlen(value), AF_INET,
					&(end->sourceip)) &&
			    !unbound_resolve(dnsctx, value,
					strlen(value), AF_INET6,
					&(end->sourceip)))
				ERR_FOUND("bad value for %ssourceip=%s\n",
					  leftright, value);
#else
			er = ttoaddr(value, 0, family, &(end->sourceip));
			if (er != NULL)
				ERR_FOUND("bad addr %ssourceip=%s [%s]",
					  leftright, value, er);
#endif
		} else {
			er = tnatoaddr(value, 0, family, &(end->sourceip));
			if (er != NULL)
				ERR_FOUND("bad numerical addr %ssourceip=%s [%s]",
					leftright, value, er);
		}
		if (!end->has_client) {
			starter_log(LOG_LEVEL_INFO,
				    "%ssourceip= used but not %ssubnet= defined, defaulting %ssubnet to %s",
				    leftright, leftright, leftright, value);
			er = addrtosubnet(&end->sourceip, &end->subnet);
			if (er != NULL) {
				ERR_FOUND("attempt to default %ssubnet from %s failed: %s",
					leftright, value, er);
			}
			end->has_client = TRUE;
			end->has_client_wildcard = FALSE;
		}
	}

	/* copy certificate path name */
	if (end->strings_set[KSCF_CERT])
		end->cert = clone_str(end->strings[KSCF_CERT], "KSCF_CERT");

	if (end->strings_set[KSCF_CA])
		end->ca = clone_str(end->strings[KSCF_CA], "KSCF_CA");

	if (end->strings_set[KSCF_UPDOWN])
		end->updown = clone_str(end->strings[KSCF_UPDOWN], "KSCF_UPDOWN");

	if (end->strings_set[KSCF_PROTOPORT]) {
		err_t ugh;
		char *value = end->strings[KSCF_PROTOPORT];

		ugh = ttoprotoport(value, 0, &end->protocol, &end->port,
				   &end->has_port_wildcard);

		if (ugh != NULL)
			ERR_FOUND("bad %sprotoport=%s [%s]", leftright, value,
				  ugh);
	}

	if (end->strings_set[KSCF_ADDRESSPOOL]) {
		char *addresspool = end->strings[KSCF_ADDRESSPOOL];

		if (end->strings_set[KSCF_SUBNET])
			ERR_FOUND("cannot specify both %ssubnet= and %saddresspool=",
				leftright, leftright);
		starter_log(LOG_LEVEL_DEBUG,
			    "connection's  %saddresspool set to: %s",
			    leftright, end->strings[KSCF_ADDRESSPOOL] );

		er = ttorange(addresspool, 0, AF_INET, &end->pool_range, TRUE);
		if (er != NULL)
			ERR_FOUND("bad %saddresspool=%s [%s]", leftright,
					addresspool, er);
	}

	if (end->options_set[KNCF_XAUTHSERVER] ||
	    end->options_set[KNCF_XAUTHCLIENT])
		conn_st->policy |= POLICY_XAUTH;

	/*
	   KSCF_SUBNETWITHIN    --- not sure what to do with it.
	   KSCF_ESPENCKEY       --- todo (manual keying)
	   KSCF_ESPAUTHKEY      --- todo (manual keying)
	   KSCF_SOURCEIP     = 16,
	   KSCF_MAX          = 19
	 */

	if (err)
		*perr = err_str;
	return err;
#  undef ERR_FOUND
}
Пример #9
0
/**
 * Set up hardcoded defaults, from data in programs/pluto/constants.h
 *
 * @param cfg starter_config struct
 * @return void
 */
void ipsecconf_default_values(struct starter_config *cfg)
{
	if (!cfg)
		return;

	zero(cfg);

	TAILQ_INIT(&cfg->conns);

	cfg->setup.options[KBF_FRAGICMP] = TRUE;
	cfg->setup.options[KBF_HIDETOS]  = TRUE;
	cfg->setup.options[KBF_PLUTORESTARTONCRASH]  = TRUE;
	cfg->setup.options[KBF_PLUTOSTDERRLOGTIME]  = FALSE;
	cfg->setup.options[KBF_UNIQUEIDS] = TRUE;
        /* XXX not yet: cfg->setup.options[KBF_PLUTOFORK] = FALSE; */
	cfg->setup.options[KBF_IKEPORT]    = IKE_UDP_PORT;
	cfg->setup.options[KBF_NATIKEPORT] = NAT_IKE_UDP_PORT;
	cfg->setup.options[KBF_NHELPERS]  = -1; /* MCR XXX */
	cfg->setup.options[KBF_KEEPALIVE] = 0;
	cfg->setup.options[KBF_SECCTX]    = SECCTX;
	cfg->setup.options[KBF_DISABLEPORTFLOATING]= FALSE;
	cfg->setup.options[KBF_FORCE_KEEPALIVE]= FALSE;

	cfg->conn_default.options[KBF_NAT_KEEPALIVE] = TRUE;    /* per conn */
	cfg->conn_default.options[KBF_TYPE] = KS_TUNNEL;

	/*Cisco interop: remote peer type*/
	cfg->conn_default.options[KBF_INITIAL_CONTACT] = FALSE;
	/* cfg->conn_default.options[KBF_CISCO_UNITY] = FALSE; */
	cfg->conn_default.options[KBF_SEND_VENDORID] = FALSE;

	cfg->conn_default.options[KBF_REMOTEPEERTYPE] = NON_CISCO;

	cfg->conn_default.options[KBF_SHA2_TRUNCBUG] = FALSE;

	cfg->conn_default.options[KBF_IKEV1_NATT] = natt_both;

	/*Network Manager support*/
	cfg->conn_default.options[KBF_NMCONFIGURED]   = FALSE;

	cfg->conn_default.options[KBF_LOOPBACK]      = FALSE;
	cfg->conn_default.options[KBF_LABELED_IPSEC] = FALSE;
#if 0
	cfg->conn_default.options[KBF_XAUTHBY] = XAUTHBY_FILE;
	cfg->conn_default.options[KBF_XAUTHFAIL] = XAUTHFAIL_HARD;
#endif

	cfg->conn_default.policy = POLICY_RSASIG | POLICY_TUNNEL |
				   POLICY_ENCRYPT | POLICY_PFS;
	cfg->conn_default.policy |= POLICY_IKEV2_ALLOW;         /* ikev2=yes */
	cfg->conn_default.policy |= POLICY_SAREF_TRACK;         /* sareftrack=yes */
	/* cfg->conn_default.policy |= POLICY_IKE_FRAG_ALLOW; */     /* ike_frag=yes */

	cfg->conn_default.options[KBF_IKELIFETIME] = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT;

	cfg->conn_default.options[KBF_SALIFETIME]  = SA_LIFE_DURATION_DEFAULT;
	cfg->conn_default.options[KBF_REKEYMARGIN] = SA_REPLACEMENT_MARGIN_DEFAULT;
	cfg->conn_default.options[KBF_REKEYFUZZ]   = SA_REPLACEMENT_FUZZ_DEFAULT;
	cfg->conn_default.options[KBF_KEYINGTRIES] = SA_REPLACEMENT_RETRIES_DEFAULT;

	/* now here is a sticker.. we want it on. But pluto has to be smarter first */
	cfg->conn_default.options[KBF_OPPOENCRYPT] = FALSE;

	cfg->conn_default.options[KBF_CONNADDRFAMILY] = AF_INET;

	cfg->conn_default.left.addr_family = AF_INET;
	anyaddr(AF_INET, &cfg->conn_default.left.addr);
	cfg->conn_default.left.nexttype  = KH_NOTSET;
	anyaddr(AF_INET, &cfg->conn_default.left.nexthop);

	cfg->conn_default.right.addr_family = AF_INET;
	anyaddr(AF_INET, &cfg->conn_default.right.addr);
	cfg->conn_default.right.nexttype = KH_NOTSET;
	anyaddr(AF_INET, &cfg->conn_default.right.nexthop);

	/* default is to look in DNS */
	cfg->conn_default.left.key_from_DNS_on_demand = TRUE;
	cfg->conn_default.right.key_from_DNS_on_demand = TRUE;


	cfg->conn_default.options[KBF_AUTO] = STARTUP_NO;
	cfg->conn_default.state = STATE_LOADED;

	cfg->ctlbase = clone_str(CTL_FILE, "default base");
}
Пример #10
0
/**
 * Validate that yes in fact we are one side of the tunnel
 *
 * The function checks that IP addresses are valid, nexthops are
 * present (if needed) as well as policies, and sets the leftID
 * from the left= if it isn't set.
 *
 * @param conn_st a connection definition
 * @param end a connection end
 * @param left boolean (are we 'left'? 1 = yes, 0 = no)
 * @param perr pointer to char containing error value
 * @return bool TRUE if failed
 */
static bool validate_end(struct starter_conn *conn_st
			, struct starter_end *end
			, bool left
			, bool resolvip UNUSED
			, err_t *perr)
{
    err_t er = NULL;
    char *err_str = NULL;
    const char *leftright=(left ? "left" : "right");
    int family = conn_st->options[KBF_CONNADDRFAMILY];
    bool err = FALSE;

#define ERR_FOUND(args...) do { err += error_append(&err_str, ##args); } while(0)

    if(!end->options_set[KNCF_IP]) {
	conn_st->state = STATE_INCOMPLETE;
    }

    end->addrtype=end->options[KNCF_IP];
    end->addr_family = family;

    /* validate the KSCF_IP/KNCF_IP */
    switch(end->addrtype) {
    case KH_ANY:
	anyaddr(family, &(end->addr));
	break;

    case KH_IFACE:
	/* generally, this doesn't show up at this stage */

	break;

    case KH_IPADDR:
        /* right=/left= */
	assert(end->strings[KSCF_IP] != NULL);

	if (end->strings[KSCF_IP][0]=='%') {
	    if (end->iface) pfree(end->iface);
            end->iface = clone_str(end->strings[KSCF_IP] + 1, "KH_IPADDR end->iface");
	    if (starter_iface_find(end->iface, family, &(end->addr),
				   &(end->nexthop)) == -1) {
	        conn_st->state = STATE_INVALID;
	    }
	    /* not numeric, so set the type to the iface type */
	    end->addrtype = KH_IFACE;
	    break;
	}

        er = ttoaddr_num(end->strings[KNCF_IP], 0, family, &(end->addr));
	if(er) {
	    /* not numeric, so set the type to the string type */
	    end->addrtype = KH_IPHOSTNAME;
	}

        if(end->id == NULL) {
            char idbuf[ADDRTOT_BUF];
            addrtot(&end->addr, 0, idbuf, sizeof(idbuf));

            end->id= clone_str(idbuf, "end id");
        }
	break;

    case KH_OPPO:
	conn_st->policy |= POLICY_OPPO;
	break;

    case KH_OPPOGROUP:
	conn_st->policy |= POLICY_OPPO|POLICY_GROUP;
	break;

    case KH_GROUP:
	conn_st->policy |= POLICY_GROUP;
	break;

    case KH_IPHOSTNAME:
        /* XXX */
	break;

    case KH_DEFAULTROUTE:
	break;

    case KH_NOTSET:
	break;
    }

    /* validate the KSCF_SUBNET */
    if(end->strings_set[KSCF_SUBNET])
    {
	char *value = end->strings[KSCF_SUBNET];

        if ( ((strlen(value)>=6) && (strncmp(value,"vhost:",6)==0)) ||
	     ((strlen(value)>=5) && (strncmp(value,"vnet:",5)==0)) ) {
	    er = NULL;
	    end->virt = clone_str(value, "end->virt");
	}
	else {
	    end->has_client = TRUE;
	    er = ttosubnet(value, 0, 0, &(end->subnet));
	}
	if (er) ERR_FOUND("bad subnet %ssubnet=%s [%s] family=%s", leftright, value, er, family2str(family));
    }

    /* set nexthop address to something consistent, by default */
    anyaddr(family, &end->nexthop);
    anyaddr(addrtypeof(&end->addr), &end->nexthop);

    /* validate the KSCF_NEXTHOP */
    if(end->strings_set[KSCF_NEXTHOP])
    {
	char *value = end->strings[KSCF_NEXTHOP];

	if(strcasecmp(value, "%defaultroute")==0) {
	    end->nexttype=KH_DEFAULTROUTE;
	} else {
            if (tnatoaddr(value, strlen(value), AF_INET,
                          &(end->nexthop)) != NULL &&
                tnatoaddr(value, strlen(value), AF_INET6,
                          &(end->nexthop)) != NULL) {
                er = ttoaddr(value, 0, family, &(end->nexthop));
                if (er) ERR_FOUND("bad addr %snexthop=%s [%s]", leftright, value, er);
            }
            end->nexttype = KH_IPADDR;
	}
    } else {
      if (end->addrtype == KH_DEFAULTROUTE) {
        end->nexttype = KH_DEFAULTROUTE;
      }
      anyaddr(family, &end->nexthop);
    }

    /* validate the KSCF_ID */
    if(end->strings_set[KSCF_ID])
    {
	char *value = end->strings[KSCF_ID];

        pfreeany(end->id);
        end->id = clone_str(value, "end->id");
    }

    if(end->options_set[KSCF_RSAKEY1]) {
	end->rsakey1_type = end->options[KSCF_RSAKEY1];
	end->rsakey2_type = end->options[KSCF_RSAKEY2];

	switch(end->rsakey1_type) {
	case PUBKEY_DNS:
	case PUBKEY_DNSONDEMAND:
	    end->key_from_DNS_on_demand = TRUE;
	    break;

	default:
	    end->key_from_DNS_on_demand = FALSE;
	    /* validate the KSCF_RSAKEY1/RSAKEY2 */
	    if(end->strings[KSCF_RSAKEY1] != NULL)
	    {
		char *value = end->strings[KSCF_RSAKEY1];

                pfreeany(end->rsakey1);
                end->rsakey1 = (unsigned char *)clone_str(value,"end->rsakey1");
	    }
	    if(end->strings[KSCF_RSAKEY2] != NULL)
	    {
		char *value = end->strings[KSCF_RSAKEY2];

                pfreeany(end->rsakey2);
                end->rsakey2 = (unsigned char *)clone_str(value,"end->rsakey2");
	    }
	}
    }

    /* validate the KSCF_SOURCEIP, if any, and if set,
     * set the subnet to same value, if not set.
     */
    if(end->strings_set[KSCF_SOURCEIP])
    {
	char *value = end->strings[KSCF_SOURCEIP];

	if (tnatoaddr(value, strlen(value), AF_INET, &(end->sourceip)) != NULL
	    && tnatoaddr(value, strlen(value), AF_INET6, &(end->sourceip)) != NULL) {

	    er = ttoaddr(value, 0, 0, &(end->sourceip));
	    if (er) ERR_FOUND("bad addr %ssourceip=%s [%s]", leftright, value, er);

	} else {
		er = tnatoaddr(value, 0, 0, &(end->sourceip));
		if (er) ERR_FOUND("bad numerical addr %ssourceip=%s [%s]", leftright, value, er);
	}

	if(!end->has_client) {
	    starter_log(LOG_LEVEL_INFO, "defaulting %ssubnet to %s\n", leftright, value);
	    er = addrtosubnet(&end->sourceip, &end->subnet);
	    if (er) ERR_FOUND("attempt to default %ssubnet from %s failed: %s", leftright, value, er);
	    end->has_client = TRUE;
	    end->has_client_wildcard = FALSE;
	}
    }

    /* copy certificate path name */
    if(end->strings_set[KSCF_CERT]) {
        end->cert = clone_str(end->strings[KSCF_CERT], "KSCF_CERT");
    }

    if(end->strings_set[KSCF_CA]) {
        end->ca = clone_str(end->strings[KSCF_CA], "KSCF_CA");
    }

    if(end->strings_set[KSCF_UPDOWN]) {
        end->updown = clone_str(end->strings[KSCF_UPDOWN], "KSCF_UPDOWN");
    }

    if(end->strings_set[KSCF_PROTOPORT]) {
	err_t ugh;
	char *value = end->strings[KSCF_PROTOPORT];

	ugh = ttoprotoport(value, 0, &end->protocol, &end->port, &end->has_port_wildcard);

	if (ugh) ERR_FOUND("bad %sprotoport=%s [%s]", leftright, value, ugh);
    }

    if (end->options_set[KNCF_XAUTHSERVER] ||
        end->options_set[KNCF_XAUTHCLIENT]) {
	conn_st->policy |= POLICY_XAUTH;
    }

    /*
    KSCF_SUBNETWITHIN    --- not sure what to do with it.
    KSCF_ESPENCKEY       --- todo (manual keying)
    KSCF_ESPAUTHKEY      --- todo (manual keying)
    KSCF_SOURCEIP     = 16,
    KSCF_MAX          = 19
    */

    if(err) *perr = err_str;
    return err;
#  undef ERR_FOUND
}
Пример #11
0
void recv_pcap_packet_gen(u_char *user,
			  const struct pcap_pkthdr *h,
			  const u_char *bytes)
{
	struct msg_digest *md;
	u_int32_t *dlt;
	struct iphdr  *ip;
	struct udphdr *udp;
	u_char    *ike;
	const struct iface_port *ifp = &if1;
	int packet_len;
	err_t from_ugh;

	union {
		struct sockaddr sa;
		struct sockaddr_in sa_in4;
		struct sockaddr_in6 sa_in6;
	} from;

	md = alloc_md();
	dlt = (u_int32_t *)bytes;
	if (*dlt != PF_INET)
		return;

	ip  = (struct iphdr *)(dlt + 1);
	udp = (struct udphdr *)(dlt + ip->ihl + 1);
	ike = (u_char *)(udp + 1);

	from.sa_in4.sin_addr.s_addr = ip->saddr;
	from.sa_in4.sin_port        = udp->source;

	md->iface = ifp;
	packet_len = h->len - (ike - bytes);

	happy(anyaddr(addrtypeof(&ifp->ip_addr), &md->sender));

	from_ugh = initaddr((void *) &from.sa_in4.sin_addr,
			    sizeof(from.sa_in4.sin_addr),
			    AF_INET, &md->sender);
	setportof(from.sa_in4.sin_port, &md->sender);
	md->sender_port = ntohs(from.sa_in4.sin_port);

	cur_from      = &md->sender;
	cur_from_port = md->sender_port;

	/* Clone actual message contents
	 * and set up md->packet_pbs to describe it.
	 */
	init_pbs(&md->packet_pbs,
		 clone_bytes(ike, packet_len,
			     "message buffer in comm_handle()"),
		 packet_len, "packet");

	DBG_log("*received %d bytes from %s:%u on %s (port=%d)",
		(int) pbs_room(&md->packet_pbs),
		ip_str(&md->sender), (unsigned) md->sender_port,
		ifp->ip_dev->id_rname,
		ifp->port);

	DBG_dump("", md->packet_pbs.start, pbs_room(&md->packet_pbs));

	process_packet(&md);

	if (md != NULL)
		release_md(md);

	cur_state = NULL;
	reset_cur_connection();
	cur_from = NULL;
}
Пример #12
0
struct raw_iface *
find_raw_ifaces4(void)
{
    static const int on = TRUE;	/* by-reference parameter; constant, we hope */
    int j;	/* index into buf */
    static int    num=64;    /* number of interfaces */
    struct ifconf ifconf;
    struct ifreq *buf;	     /* for list of interfaces -- arbitrary limit */
    struct raw_iface *rifaces = NULL;
    int master_sock = safe_socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);    /* Get a UDP socket */

    /* get list of interfaces with assigned IPv4 addresses from system */

    if (master_sock == -1)
	exit_log_errno((e, "socket() failed in find_raw_ifaces4()"));

    if (setsockopt(master_sock, SOL_SOCKET, SO_REUSEADDR
		   , (const void *)&on, sizeof(on)) < 0)
	    exit_log_errno((e, "setsockopt() in find_raw_ifaces4()"));

    /* bind the socket */
    {
	ip_address any;

	happy(anyaddr(AF_INET, &any));
	setportof(htons(pluto_port), &any);
	if (bind(master_sock, sockaddrof(&any), sockaddrlenof(&any)) < 0)
	    exit_log_errno((e, "bind() failed in find_raw_ifaces4()"));
    }

    buf = NULL;
   
    /* a million interfaces is probably the maximum, ever... */
    while(num < (1024*1024)) {
	    /* Get local interfaces.  See netdevice(7). */
	    ifconf.ifc_len = num * sizeof(struct ifreq);
	    buf = (void *) realloc(buf, ifconf.ifc_len);
	    if (!buf)
		    exit_log_errno((e, "realloc of %d in find_raw_ifaces4()",
				    ifconf.ifc_len));
	    memset(buf, 0, num*sizeof(struct ifreq));
	    ifconf.ifc_buf = (void *) buf;
	    
	    if (ioctl(master_sock, SIOCGIFCONF, &ifconf) == -1)
		    exit_log_errno((e, "ioctl(SIOCGIFCONF) in find_raw_ifaces4()"));
	    
	    /* if we got back less than we asked for, we have them all */
	    if (ifconf.ifc_len < (int)(sizeof(struct ifreq) * num))
		    break;
	    
	    /* try again and ask for more this time */
	    num *= 2;
    }
  
    /* Add an entry to rifaces for each interesting interface. */
    for (j = 0; (j+1) * sizeof(struct ifreq) <= (size_t)ifconf.ifc_len; j++)
    {
	struct raw_iface ri;
	const struct sockaddr_in *rs = (struct sockaddr_in *) &buf[j].ifr_addr;
	struct ifreq auxinfo;

	/* ignore all but AF_INET interfaces */
	if (rs->sin_family != AF_INET)
	    continue;	/* not interesting */

	/* build a NUL-terminated copy of the rname field */
	memcpy(ri.name, buf[j].ifr_name, IFNAMSIZ);
	ri.name[IFNAMSIZ] = '\0';

	/* ignore if our interface names were specified, and this isn't one */
	if (pluto_ifn_roof != 0)
	{
	    int i;

	    for (i = 0; i != pluto_ifn_roof; i++)
		if (streq(ri.name, pluto_ifn[i]))
		    break;
	    if (i == pluto_ifn_roof)
		continue;	/* not found -- skip */
	}

	/* Find out stuff about this interface.  See netdevice(7). */
	zero(&auxinfo);	/* paranoia */
	memcpy(auxinfo.ifr_name, buf[j].ifr_name, IFNAMSIZ);
	if (ioctl(master_sock, SIOCGIFFLAGS, &auxinfo) == -1)
	    exit_log_errno((e
		, "ioctl(SIOCGIFFLAGS) for %s in find_raw_ifaces4()"
		, ri.name));
	if (!(auxinfo.ifr_flags & IFF_UP))
	   {
		DBG(DBG_CONTROL, DBG_log("Ignored interface %s - it is not up"
	    , ri.name));
	    continue;	/* ignore an interface that isn't UP */
	   }
        if (auxinfo.ifr_flags & IFF_SLAVE)
	   {
		DBG(DBG_CONTROL, DBG_log("Ignored interface %s - it is a slave interface"
	    , ri.name));
            continue;   /* ignore slave interfaces; they share IPs with their master */
	   }

	/* ignore unconfigured interfaces */
	if (rs->sin_addr.s_addr == 0)
	   {
		DBG(DBG_CONTROL, DBG_log("Ignored interface %s - it is unconfigured"
	    , ri.name));
	    continue;
	   }

	happy(initaddr((const void *)&rs->sin_addr, sizeof(struct in_addr)
	    , AF_INET, &ri.addr));

	DBG(DBG_CONTROL, DBG_log("found %s with address %s"
	    , ri.name, ip_str(&ri.addr)));
	ri.next = rifaces;
	rifaces = clone_thing(ri, "struct raw_iface");
    }

    close(master_sock);

    return rifaces;
}
Пример #13
0
struct raw_iface *find_raw_ifaces4(void)
{
	static const int on = TRUE;	/* by-reference parameter; constant, we hope */
	int j;	/* index into buf */
	struct ifconf ifconf;
	struct ifreq *buf = NULL;	/* for list of interfaces -- arbitrary limit */
	struct ifreq *bp;	/* cursor into buf */
	struct raw_iface *rifaces = NULL;
	int master_sock = safe_socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);        /* Get a UDP socket */

	/*
	 * Current upper bound on number of interfaces.
	 * Tricky: because this is a static, we won't have to start from
	 * 64 in subsequent calls.
	 */
	static int num = 64;	/* number of interfaces */

	/* get list of interfaces with assigned IPv4 addresses from system */

	if (master_sock == -1)
		exit_log_errno((e, "socket() failed in find_raw_ifaces4()"));

	if (setsockopt(master_sock, SOL_SOCKET, SO_REUSEADDR,
		       (const void *)&on, sizeof(on)) < 0)
		exit_log_errno((e, "setsockopt() in find_raw_ifaces4()"));

	/* bind the socket */
	{
		ip_address any;

		happy(anyaddr(AF_INET, &any));
		setportof(htons(pluto_port), &any);
		if (bind(master_sock, sockaddrof(&any),
			 sockaddrlenof(&any)) < 0)
			exit_log_errno((e,
					"bind() failed in find_raw_ifaces4()"));
	}

	/* a million interfaces is probably the maximum, ever... */
	for (; num < (1024 * 1024); num *= 2) {
		/* Get num local interfaces.  See netdevice(7). */
		ifconf.ifc_len = num * sizeof(struct ifreq);
		buf = realloc(buf, ifconf.ifc_len);
		if (buf == NULL) {
			exit_log_errno((e,
					"realloc of %d in find_raw_ifaces4()",
					ifconf.ifc_len));
		}
		memset(buf, 0xDF, ifconf.ifc_len);	/* stomp */
		ifconf.ifc_buf = (void *) buf;

		if (ioctl(master_sock, SIOCGIFCONF, &ifconf) == -1)
			exit_log_errno((e,
					"ioctl(SIOCGIFCONF) in find_raw_ifaces4()"));


		/* if we got back less than we asked for, we have them all */
		if (ifconf.ifc_len < (int)(sizeof(struct ifreq) * num))
			break;
	}

	/* Add an entry to rifaces for each interesting interface.
	   On Apple, the size of struct ifreq depends on the contents of
	   the union. See if.h */
	for (bp = buf, j = 0;
	     bp < (unsigned char *)buf + (size_t)ifconf.ifc_len;
	     bp = (struct ifreq *)
		((unsigned char *)bp +_SIZEOF_ADDR_IFREQ(*bp)),
	     j++) {
		struct raw_iface ri;
		const struct sockaddr_in *rs =
			(struct sockaddr_in *) &bp->ifr_addr;
		struct ifreq auxinfo;

		/* ignore all but AF_INET interfaces */
		if (rs->sin_family != AF_INET)
			continue; /* not interesting */

		/* build a NUL-terminated copy of the rname field */
		memcpy(ri.name, bp->ifr_name, IFNAMSIZ);
		ri.name[IFNAMSIZ] = '\0';

		/* ignore if our interface names were specified, and this isn't one */
		if (pluto_ifn_roof != 0) {
			int i;

			for (i = 0; i != pluto_ifn_roof; i++)
				if (streq(ri.name, pluto_ifn[i]))
					break;
			if (i == pluto_ifn_roof)
				continue; /* not found -- skip */
		}

		/* Find out stuff about this interface.  See netdevice(7). */
		zero(&auxinfo); /* paranoia */
		memcpy(auxinfo.ifr_name, bp->ifr_name, IFNAMSIZ);
		if (ioctl(master_sock, SIOCGIFFLAGS, &auxinfo) == -1) {
			exit_log_errno((e,
					"ioctl(SIOCGIFFLAGS) for %s in find_raw_ifaces4()",
					ri.name));
		}
		if (!(auxinfo.ifr_flags & IFF_UP))
			continue; /* ignore an interface that isn't UP */

		/* ignore unconfigured interfaces */
		if (rs->sin_addr.s_addr == 0)
			continue;

		happy(initaddr((const void *)&rs->sin_addr,
			       sizeof(struct in_addr),
			       AF_INET, &ri.addr));

		DBG(DBG_CONTROL, {
			ipstr_buf b;
			DBG_log("found %s with address %s",
				ri.name, ipstr(&ri.addr, &b));
		});
		ri.next = rifaces;
		rifaces = clone_thing(ri, "struct raw_iface");
	}
Пример #14
0
int
main(int argc, char **argv)
{
	int i, nspis;
	char *endptr;
	int said_opt = 0;

	const char* error_s = NULL;
	char ipaddr_txt[ADDRTOT_BUF];
	int debug = 0;
	int j;
	struct said_af said_af_array[4];

	int error = 0;

	struct sadb_ext *extensions[SADB_EXT_MAX + 1];
	struct sadb_msg *pfkey_msg;
#if 0
	ip_address pfkey_address_s_ska;
#endif
	
	program_name = argv[0];
	for(i = 0; i < 4; i++) {
		memset(&said_af_array[i], 0, sizeof(struct said_af));
	}

        if(argc > 1 && strcmp(argv[1], "--debug") == 0) {
		debug = 1;
		if(debug) {
			fprintf(stdout, "\"--debug\" option requested.\n");
		}
		argv += 1;
		argc -= 1;
		pfkey_lib_debug = 1;
        }

	if(debug) {
		fprintf(stdout, "argc=%d (%d incl. --debug option).\n",
			argc,
			argc + 1);
	}

        if(argc > 1 && strcmp(argv[1], "--label") == 0) {
		if(argc > 2) {
			program_name = malloc(strlen(argv[0])
					      + 10 /* update this when changing the sprintf() */
					      + strlen(argv[2]));
			sprintf(program_name, "%s --label %s",
				argv[0],
				argv[2]);
			if(debug) {
				fprintf(stdout, "using \"%s\" as a label.\n", program_name);
			}
			argv += 2;
			argc -= 2;
		} else {
			fprintf(stderr, "%s: --label option requires an argument.\n",
				program_name);
			exit(1);
		}
        }
  
	if(debug) {
		fprintf(stdout, "...After check for --label option.\n");
	}

	if(argc == 1) {
		system("cat /proc/net/ipsec_spigrp");
		exit(0);
	}

	if(debug) {
		fprintf(stdout, "...After check for no option to print /proc/net/ipsec_spigrp.\n");
	}

        if(strcmp(argv[1], "--help") == 0) {
		if(debug) {
			fprintf(stdout, "\"--help\" option requested.\n");
		}
                usage(program_name);
                exit(1);
        }

	if(debug) {
		fprintf(stdout, "...After check for --help option.\n");
	}

        if(strcmp(argv[1], "--version") == 0) {
		if(debug) {
			fprintf(stdout, "\"--version\" option requested.\n");
		}
		fprintf(stdout, "%s %s\n", me, ipsec_version_code());
		fprintf(stdout, "See `ipsec --copyright' for copyright information.\n");
                exit(1);
        }

	if(debug) {
		fprintf(stdout, "...After check for --version option.\n");
	}

        if(strcmp(argv[1], "--said") == 0) {
		if(debug) {
			fprintf(stdout, "processing %d args with --said flag.\n", argc);
		}
		said_opt = 1;
        }
	
	if(debug) {
		fprintf(stdout, "...After check for --said option.\n");
	}

	if(said_opt) {
		if (argc < 3 /*|| argc > 5*/) {
			fprintf(stderr, "expecting 3 or more args with --said, got %d.\n", argc);
			usage(program_name);
                	exit(1);
		}
		nspis = argc - 2;
	} else {
		if ((argc < 5) || (argc > 17) || ((argc % 4) != 1)) {
			fprintf(stderr, "expecting 5 or more args without --said, got %d.\n", argc);
			usage(program_name);
                	exit(1);
		}
		nspis = argc / 4;
	}

	if(debug) {
		fprintf(stdout, "processing %d nspis.\n", nspis);
	}

	for(i = 0; i < nspis; i++) {
		if(debug) {
			fprintf(stdout, "processing spi #%d.\n", i);
		}

		if(said_opt) {
			error_s = ttosa((const char *)argv[i+2], 0, (ip_said*)&(said_af_array[i].said));
			if(error_s != NULL) {
				fprintf(stderr, "%s: Error, %s converting --sa argument:%s\n",
					program_name, error_s, argv[i+2]);
				exit (1);
			}
			said_af_array[i].af = addrtypeof(&(said_af_array[i].said.dst));
			if(debug) {
				addrtot(&said_af_array[i].said.dst, 0, ipaddr_txt, sizeof(ipaddr_txt));
				fprintf(stdout, "said[%d].dst=%s.\n", i, ipaddr_txt);
			}
		} else {
			if(!strcmp(argv[i*4+4], "ah")) {
				said_af_array[i].said.proto = SA_AH;
			}
			if(!strcmp(argv[i*4+4], "esp")) {
				said_af_array[i].said.proto = SA_ESP;
			}
			if(!strcmp(argv[i*4+4], "tun")) {
				said_af_array[i].said.proto = SA_IPIP;
			}
			if(!strcmp(argv[i*4+4], "comp")) {
				said_af_array[i].said.proto = SA_COMP;
			}
			if(said_af_array[i].said.proto == 0) {
				fprintf(stderr, "%s: Badly formed proto: %s\n",
					program_name, argv[i*4+4]);
				exit(1);
			}
			said_af_array[i].said.spi = htonl(strtoul(argv[i*4+3], &endptr, 0));
			if(!(endptr == argv[i*4+3] + strlen(argv[i*4+3]))) {
				fprintf(stderr, "%s: Badly formed spi: %s\n",
					program_name, argv[i*4+3]);
				exit(1);
			}
			if(!strcmp(argv[i*4+1], "inet")) {
				said_af_array[i].af = AF_INET;
			}
			if(!strcmp(argv[i*4+1], "inet6")) {
				said_af_array[i].af = AF_INET6;
			}
			if((said_af_array[i].af != AF_INET) && (said_af_array[i].af != AF_INET6)) {
				fprintf(stderr, "%s: Address family %s not supported\n",
					program_name, argv[i*4+1]);
				exit(1);
			}
			error_s = ttoaddr(argv[i*4+2], 0, said_af_array[i].af, &(said_af_array[i].said.dst));
			if(error_s != NULL) {
				fprintf(stderr, "%s: Error, %s converting %dth address argument:%s\n",
					program_name, error_s, i, argv[i*4+2]);
				exit (1);
			}
		}
		if(debug) {
			fprintf(stdout, "SA %d contains: ", i+1);
			fprintf(stdout, "\n");
			fprintf(stdout, "proto = %d\n", said_af_array[i].said.proto);
			fprintf(stdout, "spi = %08x\n", said_af_array[i].said.spi);
			addrtot(&said_af_array[i].said.dst, 0, ipaddr_txt, sizeof(ipaddr_txt));
			fprintf(stdout, "edst = %s\n", ipaddr_txt);
		}
	}	

	if(debug) {
		fprintf(stdout, "Opening pfkey socket.\n");
	}

	if((pfkey_sock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2) ) < 0) {
		fprintf(stderr, "%s: Trouble opening PF_KEY family socket with error: ",
			program_name);
		switch(errno) {
		case ENOENT:
			fprintf(stderr, "device does not exist.  See FreeS/WAN installation procedure.\n");
			break;
		case EACCES:
			fprintf(stderr, "access denied.  ");
			if(getuid() == 0) {
				fprintf(stderr, "Check permissions.  Should be 600.\n");
			} else {
				fprintf(stderr, "You must be root to open this file.\n");
			}
			break;
		case EUNATCH:
			fprintf(stderr, "Netlink not enabled OR KLIPS not loaded.\n");
			break;
		case ENODEV:
			fprintf(stderr, "KLIPS not loaded or enabled.\n");
			break;
		case EBUSY:
			fprintf(stderr, "KLIPS is busy.  Most likely a serious internal error occured in a previous command.  Please report as much detail as possible to development team.\n");
			break;
		case EINVAL:
			fprintf(stderr, "Invalid argument, KLIPS not loaded or check kernel log messages for specifics.\n");
			break;
		case ENOBUFS:
			fprintf(stderr, "No kernel memory to allocate SA.\n");
			break;
		case ESOCKTNOSUPPORT:
			fprintf(stderr, "Algorithm support not available in the kernel.  Please compile in support.\n");
			break;
		case EEXIST:
			fprintf(stderr, "SA already in use.  Delete old one first.\n");
			break;
		case ENXIO:
			fprintf(stderr, "SA does not exist.  Cannot delete.\n");
			break;
		case EAFNOSUPPORT:
			fprintf(stderr, "KLIPS not loaded or enabled.\n");
			break;
		default:
			fprintf(stderr, "Unknown file open error %d.  Please report as much detail as possible to development team.\n", errno);
		}
		exit(1);
	}

	for(i = 0; i < (((nspis - 1) < 2) ? 1 : (nspis - 1)); i++) {
		if(debug) {
			fprintf(stdout, "processing %dth pfkey message.\n", i);
		}

		pfkey_extensions_init(extensions);
		for(j = 0; j < ((nspis == 1) ? 1 : 2); j++) {
			if(debug) {
				fprintf(stdout, "processing %dth said of %dth pfkey message.\n", j, i);
			}

			/* Build an SADB_X_GRPSA message to send down. */
			/* It needs <base, SA, SA2, address(D,D2) > minimum. */
			if(!j) {
				if((error = pfkey_msg_hdr_build(&extensions[0],
								SADB_X_GRPSA,
								proto2satype(said_af_array[i].said.proto),
								0,
								++pfkey_seq,
								getpid()))) {
					fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
						program_name, error);
					pfkey_extensions_free(extensions);
					exit(1);
				}
			} else {
				if(debug) {
					fprintf(stdout, "setting x_satype proto=%d satype=%d\n",
						said_af_array[i+j].said.proto,
						proto2satype(said_af_array[i+j].said.proto)
						);
				}

				if((error = pfkey_x_satype_build(&extensions[SADB_X_EXT_SATYPE2],
								 proto2satype(said_af_array[i+j].said.proto)
					))) {
					fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
						program_name, error);
					pfkey_extensions_free(extensions);
					exit(1);
				}
			}

			if((error = pfkey_sa_build(&extensions[!j ? SADB_EXT_SA : SADB_X_EXT_SA2],
						   !j ? SADB_EXT_SA : SADB_X_EXT_SA2,
						   said_af_array[i+j].said.spi, /* in network order */
						   0,
						   0,
						   0,
						   0,
						   0))) {
				fprintf(stderr, "%s: Trouble building sa extension, error=%d.\n",
					program_name, error);
				pfkey_extensions_free(extensions);
				exit(1);
			}
			
#if 0
			if(!j) {
				anyaddr(said_af_array[i].af, &pfkey_address_s_ska); /* Is the address family correct ?? */
				if((error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
								SADB_EXT_ADDRESS_SRC,
								0,
								0,
								sockaddrof(&pfkey_address_s_ska)))) {
					addrtot(&pfkey_address_s_ska, 0, ipaddr_txt, sizeof(ipaddr_txt));
					fprintf(stderr, "%s: Trouble building address_s extension (%s), error=%d.\n",
						program_name, ipaddr_txt, error);
					pfkey_extensions_free(extensions);
					exit(1);
				}
			}
#endif			
			if((error = pfkey_address_build(&extensions[!j ? SADB_EXT_ADDRESS_DST : SADB_X_EXT_ADDRESS_DST2],
							!j ? SADB_EXT_ADDRESS_DST : SADB_X_EXT_ADDRESS_DST2,
							0,
							0,
							sockaddrof(&said_af_array[i+j].said.dst)))) {
				addrtot(&said_af_array[i+j].said.dst,
					0, ipaddr_txt, sizeof(ipaddr_txt));
				fprintf(stderr, "%s: Trouble building address_d extension (%s), error=%d.\n",
					program_name, ipaddr_txt, error);
				pfkey_extensions_free(extensions);
				exit(1);
			}
			
		}

		if((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN))) {
			fprintf(stderr, "%s: Trouble building pfkey message, error=%d.\n",
				program_name, error);
			pfkey_extensions_free(extensions);
			pfkey_msg_free(&pfkey_msg);
			exit(1);
		}
		
		if((error = write(pfkey_sock,
				  pfkey_msg,
				  pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) !=
		   pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) {
			fprintf(stderr, "%s: pfkey write failed, returning %d with errno=%d.\n",
				program_name, error, errno);
			pfkey_extensions_free(extensions);
			pfkey_msg_free(&pfkey_msg);
			switch(errno) {
			case EACCES:
				fprintf(stderr, "access denied.  ");
				if(getuid() == 0) {
					fprintf(stderr, "Check permissions.  Should be 600.\n");
				} else {
					fprintf(stderr, "You must be root to open this file.\n");
				}
				break;
			case EUNATCH:
				fprintf(stderr, "Netlink not enabled OR KLIPS not loaded.\n");
				break;
			case EBUSY:
				fprintf(stderr, "KLIPS is busy.  Most likely a serious internal error occured in a previous command.  Please report as much detail as possible to development team.\n");
				break;
			case EINVAL:
				fprintf(stderr, "Invalid argument, check kernel log messages for specifics.\n");
				break;
			case ENODEV:
				fprintf(stderr, "KLIPS not loaded or enabled.\n");
				fprintf(stderr, "No device?!?\n");
				break;
			case ENOBUFS:
				fprintf(stderr, "No kernel memory to allocate SA.\n");
				break;
			case ESOCKTNOSUPPORT:
				fprintf(stderr, "Algorithm support not available in the kernel.  Please compile in support.\n");
				break;
			case EEXIST:
				fprintf(stderr, "SA already in use.  Delete old one first.\n");
				break;
			case ENOENT:
				fprintf(stderr, "device does not exist.  See FreeS/WAN installation procedure.\n");
				break;
			case ENXIO:
				fprintf(stderr, "SA does not exist.  Cannot delete.\n");
				break;
			default:
				fprintf(stderr, "Unknown socket write error %d.  Please report as much detail as possible to development team.\n", errno);
			}
			exit(1);
		}
		if(pfkey_msg) {
			pfkey_extensions_free(extensions);
			pfkey_msg_free(&pfkey_msg);
		}
	}

	(void) close(pfkey_sock);  /* close the socket */
	exit(0);
}
Пример #15
0
int
main(int argc, char **argv)
{
	int i, nspis;
	char *endptr;
	int said_opt = 0;

	const char* error_s = NULL;
	char ipaddr_txt[ADDRTOT_BUF];
	int j;
	struct said_af said_af_array[4];

	int error = 0;
        struct stat sts;

	struct sadb_ext *extensions[K_SADB_EXT_MAX + 1];
	struct sadb_msg *pfkey_msg;
#if 0
	ip_address pfkey_address_s_ska;
#endif
	
	progname = argv[0];
	for(i = 0; i < 4; i++) {
		memset(&said_af_array[i], 0, sizeof(struct said_af));
	}

        if(argc > 1 && strcmp(argv[1], "--debug") == 0) {
		debug = 1;
		if(debug) {
			fprintf(stdout, "\"--debug\" option requested.\n");
		}
		argv += 1;
		argc -= 1;
		pfkey_lib_debug = PF_KEY_DEBUG_PARSE_MAX;
        }

	if(debug) {
		fprintf(stdout, "argc=%d (%d incl. --debug option).\n",
			argc,
			argc + 1);
	}

        if(argc > 1 && strcmp(argv[1], "--label") == 0) {
		if(argc > 2) {
			progname = malloc(strlen(argv[0])
					      + 10 /* update this when changing the sprintf() */
					      + strlen(argv[2]));
			sprintf(progname, "%s --label %s",
				argv[0],
				argv[2]);
			if(debug) {
				fprintf(stdout, "using \"%s\" as a label.\n", progname);
			}
			argv += 2;
			argc -= 2;
		} else {
			fprintf(stderr, "%s: --label option requires an argument.\n",
				progname);
			exit(1);
		}
        }
  
	if(debug) {
		fprintf(stdout, "...After check for --label option.\n");
	}


        if ( ((stat ("/proc/net/pfkey", &sts)) == 0) )  {
                fprintf(stderr, "%s: NETKEY does not use the ipsec spigrp command. Use 'ip xfrm' instead.\n",progname);
                exit(1);
        }

        if(argc == 1) {
                int ret = 1;
                if ((stat ("/proc/net/ipsec_spigrp", &sts)) != 0)  {
                        fprintf(stderr, "%s: No spigrp - no IPsec support in kernel (are the modules loaded?)\n", progname);
                } else {
                        ret = system("cat /proc/net/ipsec_spigrp");
                        ret = ret != -1 && WIFEXITED(ret) ? WEXITSTATUS(ret) : 1;
                }
                exit(ret);
        }

	if(debug) {
		fprintf(stdout, "...After check for no option to print /proc/net/ipsec_spigrp.\n");
	}

        if(strcmp(argv[1], "--help") == 0) {
		if(debug) {
			fprintf(stdout, "\"--help\" option requested.\n");
		}
                usage(progname);
                exit(1);
        }

	if(debug) {
		fprintf(stdout, "...After check for --help option.\n");
	}

        if(strcmp(argv[1], "--version") == 0) {
		if(debug) {
			fprintf(stdout, "\"--version\" option requested.\n");
		}
                fprintf(stderr, "%s, %s\n", progname, ipsec_version_code());
                exit(1);
        }

	if(debug) {
		fprintf(stdout, "...After check for --version option.\n");
	}

        if(strcmp(argv[1], "--said") == 0) {
		if(debug) {
			fprintf(stdout, "processing %d args with --said flag.\n", argc);
		}
		said_opt = 1;
        }
	
	if(debug) {
		fprintf(stdout, "...After check for --said option.\n");
	}

	if(said_opt) {
		if (argc < 3 /*|| argc > 5*/) {
			fprintf(stderr, "expecting 3 or more args with --said, got %d.\n", argc);
			usage(progname);
                	exit(1);
		}
		nspis = argc - 2;
	} else {
		if ((argc < 5) || (argc > 17) || ((argc % 4) != 1)) {
			fprintf(stderr, "expecting 5 or more args without --said, got %d.\n", argc);
			usage(progname);
                	exit(1);
		}
		nspis = argc / 4;
	}

	if(debug) {
		fprintf(stdout, "processing %d nspis.\n", nspis);
	}

	for(i = 0; i < nspis; i++) {
		if(debug) {
			fprintf(stdout, "processing spi #%d.\n", i);
		}

		if(said_opt) {
			error_s = ttosa((const char *)argv[i+2], 0, (ip_said*)&(said_af_array[i].said));
			if(error_s != NULL) {
				fprintf(stderr, "%s: Error, %s converting --sa argument:%s\n",
					progname, error_s, argv[i+2]);
				exit (1);
			}
			said_af_array[i].af = addrtypeof(&(said_af_array[i].said.dst));
			if(debug) {
				addrtot(&said_af_array[i].said.dst, 0, ipaddr_txt, sizeof(ipaddr_txt));
				fprintf(stdout, "said[%d].dst=%s.\n", i, ipaddr_txt);
			}
		} else {
			if(!strcmp(argv[i*4+4], "ah")) {
				said_af_array[i].said.proto = SA_AH;
			}
			if(!strcmp(argv[i*4+4], "esp")) {
				said_af_array[i].said.proto = SA_ESP;
			}
			if(!strcmp(argv[i*4+4], "tun")) {
				said_af_array[i].said.proto = SA_IPIP;
			}
			if(!strcmp(argv[i*4+4], "comp")) {
				said_af_array[i].said.proto = SA_COMP;
			}
			if(said_af_array[i].said.proto == 0) {
				fprintf(stderr, "%s: Badly formed proto: %s\n",
					progname, argv[i*4+4]);
				exit(1);
			}
			said_af_array[i].said.spi = htonl(strtoul(argv[i*4+3], &endptr, 0));
			if(!(endptr == argv[i*4+3] + strlen(argv[i*4+3]))) {
				fprintf(stderr, "%s: Badly formed spi: %s\n",
					progname, argv[i*4+3]);
				exit(1);
			}
			if(!strcmp(argv[i*4+1], "inet")) {
				said_af_array[i].af = AF_INET;
			}
			if(!strcmp(argv[i*4+1], "inet6")) {
				said_af_array[i].af = AF_INET6;
			}
			if((said_af_array[i].af != AF_INET) && (said_af_array[i].af != AF_INET6)) {
				fprintf(stderr, "%s: Address family %s not supported\n",
					progname, argv[i*4+1]);
				exit(1);
			}
			error_s = ttoaddr(argv[i*4+2], 0, said_af_array[i].af, &(said_af_array[i].said.dst));
			if(error_s != NULL) {
				fprintf(stderr, "%s: Error, %s converting %dth address argument:%s\n",
					progname, error_s, i, argv[i*4+2]);
				exit (1);
			}
		}
		if(debug) {
			fprintf(stdout, "SA %d contains: ", i+1);
			fprintf(stdout, "\n");
			fprintf(stdout, "proto = %d\n", said_af_array[i].said.proto);
			fprintf(stdout, "spi = %08x\n", said_af_array[i].said.spi);
			addrtot(&said_af_array[i].said.dst, 0, ipaddr_txt, sizeof(ipaddr_txt));
			fprintf(stdout, "edst = %s\n", ipaddr_txt);
		}
	}	

	if(debug) {
		fprintf(stdout, "Opening pfkey socket.\n");
	}

	pfkey_sock = pfkey_open_sock_with_error();
	if(pfkey_sock < 0) {
	    exit(1);
	}

	for(i = 0; i < (((nspis - 1) < 2) ? 1 : (nspis - 1)); i++) {
		if(debug) {
			fprintf(stdout, "processing %dth pfkey message.\n", i);
		}

		pfkey_extensions_init(extensions);
		for(j = 0; j < ((nspis == 1) ? 1 : 2); j++) {
			if(debug) {
				fprintf(stdout, "processing %dth said of %dth pfkey message.\n", j, i);
			}

			/* Build an SADB_X_GRPSA message to send down. */
			/* It needs <base, SA, SA2, address(D,D2) > minimum. */
			if(!j) {
				if((error = pfkey_msg_hdr_build(&extensions[0],
								K_SADB_X_GRPSA,
								proto2satype(said_af_array[i].said.proto),
								0,
								++pfkey_seq,
								getpid()))) {
					fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
						progname, error);
					pfkey_extensions_free(extensions);
					exit(1);
				}
			} else {
				if(debug) {
					fprintf(stdout, "setting x_satype proto=%d satype=%d\n",
						said_af_array[i+j].said.proto,
						proto2satype(said_af_array[i+j].said.proto)
						);
				}

				if((error = pfkey_x_satype_build(&extensions[K_SADB_X_EXT_SATYPE2],
								 proto2satype(said_af_array[i+j].said.proto)
					))) {
					fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
						progname, error);
					pfkey_extensions_free(extensions);
					exit(1);
				}
			}

			if((error = pfkey_sa_build(&extensions[!j ? K_SADB_EXT_SA : K_SADB_X_EXT_SA2],
						   !j ? K_SADB_EXT_SA : K_SADB_X_EXT_SA2,
						   said_af_array[i+j].said.spi, /* in network order */
						   0,
						   0,
						   0,
						   0,
						   0))) {
				fprintf(stderr, "%s: Trouble building sa extension, error=%d.\n",
					progname, error);
				pfkey_extensions_free(extensions);
				exit(1);
			}
			
#if 0
			if(!j) {
				anyaddr(said_af_array[i].af, &pfkey_address_s_ska); /* Is the address family correct ?? */
				if((error = pfkey_address_build(&extensions[K_SADB_EXT_ADDRESS_SRC],
								K_SADB_EXT_ADDRESS_SRC,
								0,
								0,
								sockaddrof(&pfkey_address_s_ska)))) {
					addrtot(&pfkey_address_s_ska, 0, ipaddr_txt, sizeof(ipaddr_txt));
					fprintf(stderr, "%s: Trouble building address_s extension (%s), error=%d.\n",
						progname, ipaddr_txt, error);
					pfkey_extensions_free(extensions);
					exit(1);
				}
			}
#endif			
			if((error = pfkey_address_build(&extensions[!j ? SADB_EXT_ADDRESS_DST : SADB_X_EXT_ADDRESS_DST2],
							!j ? SADB_EXT_ADDRESS_DST : SADB_X_EXT_ADDRESS_DST2,
							0,
							0,
							sockaddrof(&said_af_array[i+j].said.dst)))) {
				addrtot(&said_af_array[i+j].said.dst,
					0, ipaddr_txt, sizeof(ipaddr_txt));
				fprintf(stderr, "%s: Trouble building address_d extension (%s), error=%d.\n",
					progname, ipaddr_txt, error);
				pfkey_extensions_free(extensions);
				exit(1);
			}
			
		}

		if((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN))) {
			fprintf(stderr, "%s: Trouble building pfkey message, error=%d.\n",
				progname, error);
			pfkey_extensions_free(extensions);
			pfkey_msg_free(&pfkey_msg);
			exit(1);
		}
		
		if((error = write(pfkey_sock,
				  pfkey_msg,
				  pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) !=
		   (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) {
			fprintf(stderr, "%s: pfkey write failed, returning %d with errno=%d.\n",
				progname, error, errno);
			pfkey_extensions_free(extensions);
			pfkey_msg_free(&pfkey_msg);
			pfkey_write_error(error, errno);
		}

		if(pfkey_msg) {
			pfkey_extensions_free(extensions);
			pfkey_msg_free(&pfkey_msg);
		}
	}

	(void) close(pfkey_sock);  /* close the socket */
	exit(0);
}
Пример #16
0
int main(int argc, char *argv[])
{
	__u32 spi = 0;
	int c;
	ip_said said;
	const char *error_s;
	char ipsaid_txt[SATOT_BUF];

	int outif = 0;
	int error = 0;
	ssize_t io_error;
	int argcount = argc;
	pid_t mypid;
	int listenreply = 0;

	unsigned char authalg, encryptalg;
	struct sadb_ext *extensions[K_SADB_EXT_MAX + 1];
	struct sadb_msg *pfkey_msg;
	char *edst_opt, *spi_opt, *proto_opt, *af_opt, *said_opt, *dst_opt,
	*src_opt;
	u_int32_t natt;
	u_int16_t sport, dport;
	uint32_t life[life_maxsever][life_maxtype];
	char *life_opt[life_maxsever][life_maxtype];
	struct stat sts;
	struct sadb_builds sab;

	progname = argv[0];
	mypid = getpid();
	natt = 0;
	sport = 0;
	dport = 0;

	tool_init_log();

	zero(&said);	/* OK: no pointer fields */
	edst_opt = spi_opt = proto_opt = af_opt = said_opt = dst_opt =
		src_opt = NULL;
	{
		int i, j;

		for (i = 0; i < life_maxsever; i++) {
			for (j = 0; j < life_maxtype; j++) {
				life_opt[i][j] = NULL;
				life[i][j] = 0;
			}
		}
	}

	while ((c = getopt_long(argc, argv,
				"" /*"H:P:Z:46dcA:E:e:s:a:w:i:D:S:hvgl:+:f:"*/,
				longopts, 0)) != EOF) {
		unsigned long u;
		err_t ugh;

		switch (c) {
		case 'g':
			debug = TRUE;
			pfkey_lib_debug = PF_KEY_DEBUG_PARSE_MAX;
			/* paul: this is a plutoism? cur_debugging = 0xffffffff; */
			argcount--;
			break;

		case 'R':
			listenreply = 1;
			argcount--;
			break;

		case 'r':
			dumpsaref = 1;
			argcount--;
			break;

		case 'b':  /* set the SAref to use */
			ugh = ttoulb(optarg, 0, 0, INT_MAX, &u);
			if (ugh != NULL) {
				fprintf(stderr,
					"%s: Invalid SAREFi parameter \"%s\": %s\n",
					progname, optarg, ugh);
				exit(1);
			}
			saref_me = u;
			argcount--;
			break;

		case 'B':  /* set the SAref to use for outgoing packets */
			ugh = ttoulb(optarg, 0, 0, INT_MAX, &u);
			if (ugh != NULL) {
				fprintf(stderr,
					"%s: Invalid SAREFo parameter \"%s\": %s\n",
					progname, optarg, ugh);
				exit(1);
			}
			saref_him = u;
			argcount--;
			break;

		case 'O':  /* set interface from which packet should arrive */
			ugh = ttoulb(optarg, 0, 0, INT_MAX, &u);
			if (ugh != NULL) {
				fprintf(stderr,
					"%s: Invalid outif parameter \"%s\": %s\n",
					progname, optarg, ugh);
				exit(1);
			}
			outif = u;
			argcount--;
			break;

		case 'l':
		{
			static const char combine_fmt[] = "%s --label %s";
			size_t room = strlen(argv[0]) +
					  sizeof(combine_fmt) +
					  strlen(optarg);

			progname = malloc(room);
			snprintf(progname, room, combine_fmt,
				argv[0],
				optarg);
			tool_close_log();
			tool_init_log();

			argcount -= 2;
			break;
		}
		case 'H':
			if (alg) {
				fprintf(stderr,
					"%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear'  options permitted.\n",
					progname);
				exit(1);
			}
			if (streq(optarg, "hmac-md5-96")) {
				alg = XF_AHHMACMD5;
			} else if (streq(optarg, "hmac-sha1-96")) {
				alg = XF_AHHMACSHA1;
			} else {
				fprintf(stderr,
					"%s: Unknown authentication algorithm '%s' follows '--ah' option.\n",
					progname, optarg);
				exit(1);
			}
			if (debug) {
				fprintf(stdout, "%s: Algorithm %d selected.\n",
					progname,
					alg);
			}
			break;

		case 'P':
			if (alg) {
				fprintf(stderr,
					"%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear'  options permitted.\n",
					progname);
				exit(1);
			}

			alg = decode_esp(optarg);

			if (debug) {
				fprintf(stdout, "%s: Algorithm %d selected.\n",
					progname,
					alg);
			}
			break;

		case 'Z':
			if (alg) {
				fprintf(stderr,
					"%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear'  options permitted.\n",
					progname);
				exit(1);
			}
			if (streq(optarg, "deflate")) {
				alg = XF_COMPDEFLATE;
			} else if (streq(optarg, "lzs")) {
				alg = XF_COMPLZS;
			} else {
				fprintf(stderr,
					"%s: Unknown compression algorithm '%s' follows '--comp' option.\n",
					progname, optarg);
				exit(1);
			}
			if (debug) {
				fprintf(stdout, "%s: Algorithm %d selected.\n",
					progname,
					alg);
			}
			break;

		case '4':
			if (alg) {
				fprintf(stderr,
					"%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n",
					progname);
				exit(1);
			}
			alg = XF_IP4;
			address_family = AF_INET;
			if (debug) {
				fprintf(stdout, "%s: Algorithm %d selected.\n",
					progname,
					alg);
			}
			break;

		case '6':
			if (alg) {
				fprintf(stderr,
					"%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n",
					progname);
				exit(1);
			}
			alg = XF_IP6;
			address_family = AF_INET6;
			if (debug) {
				fprintf(stdout, "%s: Algorithm %d selected.\n",
					progname,
					alg);
			}
			break;

		case 'd':
			if (alg) {
				fprintf(stderr,
					"%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear'  options permitted.\n",
					progname);
				exit(1);
			}
			alg = XF_DEL;
			if (debug) {
				fprintf(stdout, "%s: Algorithm %d selected.\n",
					progname,
					alg);
			}
			break;

		case 'c':
			if (alg) {
				fprintf(stderr,
					"%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear'  options permitted.\n",
					progname);
				exit(1);
			}
			alg = XF_CLR;
			if (debug) {
				fprintf(stdout, "%s: Algorithm %d selected.\n",
					progname,
					alg);
			}
			break;

		case 'e':
			if (said_opt) {
				fprintf(stderr,
					"%s: Error, EDST parameter redefined:%s, already defined in SA:%s\n",
					progname, optarg, said_opt);
				exit(1);
			}
			if (edst_opt) {
				fprintf(stderr,
					"%s: Error, EDST parameter redefined:%s, already defined as:%s\n",
					progname, optarg, edst_opt);
				exit(1);
			}
			error_s = ttoaddr(optarg, 0, address_family, &edst);
			if (error_s != NULL) {
				if (error_s) {
					fprintf(stderr,
						"%s: Error, %s converting --edst argument:%s\n",
						progname, error_s, optarg);
					exit(1);
				}
			}
			edst_opt = optarg;
			if (debug) {
				ipstr_buf b;

				fprintf(stdout, "%s: edst=%s.\n",
					progname,
					ipstr(&edst, &b));
			}
			break;

		case 's':
			if (said_opt != NULL) {
				fprintf(stderr,
					"%s: Error, SPI parameter redefined:%s, already defined in SA:%s\n",
					progname, optarg, said_opt);
				exit(1);
			}
			if (spi_opt != NULL) {
				fprintf(stderr,
					"%s: Error, SPI parameter redefined:%s, already defined as:%s\n",
					progname, optarg, spi_opt);
				exit(1);
			}
			ugh = ttoulb(optarg, 0, 0, 0xFFFFFFFFul, &u);
			if (ugh == NULL && u < 0x100)
				ugh = "0 - 0xFF are reserved";
			if (ugh != NULL) {
				fprintf(stderr,
					"%s: Invalid SPI parameter \"%s\": %s\n",
					progname, optarg, ugh);
				exit(1);
			}
			spi = u;
			spi_opt = optarg;
			break;

		case 'p':
			if (said_opt != NULL) {
				fprintf(stderr,
					"%s: Error, PROTO parameter redefined:%s, already defined in SA:%s\n",
					progname, optarg, said_opt);
				exit(1);
			}
			if (proto_opt != NULL) {
				fprintf(stderr,
					"%s: Error, PROTO parameter redefined:%s, already defined as:%s\n",
					progname, optarg, proto_opt);
				exit(1);
			}
			if (streq(optarg, "ah")) {
				proto = SA_AH;
			} else if (streq(optarg, "esp")) {
				proto = SA_ESP;
			} else if (streq(optarg, "tun")) {
				proto = SA_IPIP;
			} else if (streq(optarg, "comp")) {
				proto = SA_COMP;
			} else {
				fprintf(stderr,
					"%s: Invalid PROTO parameter: %s\n",
					progname, optarg);
				exit(1);
			}
			proto_opt = optarg;
			break;

		case 'a':
			if (said_opt) {
				fprintf(stderr,
					"%s: Error, ADDRESS FAMILY parameter redefined:%s, already defined in SA:%s\n",
					progname, optarg, said_opt);
				exit(1);
			}
			if (af_opt) {
				fprintf(stderr,
					"%s: Error, ADDRESS FAMILY parameter redefined:%s, already defined as:%s\n",
					progname, optarg, af_opt);
				exit(1);
			}
			if (streq(optarg, "inet")) {
				address_family = AF_INET;
				/* currently we ensure that all addresses belong to the same address family */
				anyaddr(address_family, &dst);
				anyaddr(address_family, &edst);
				anyaddr(address_family, &src);
			} else if (streq(optarg, "inet6")) {
				address_family = AF_INET6;
				/* currently we ensure that all addresses belong to the same address family */
				anyaddr(address_family, &dst);
				anyaddr(address_family, &edst);
				anyaddr(address_family, &src);
			} else {
				fprintf(stderr,
					"%s: Invalid ADDRESS FAMILY parameter: %s.\n",
					progname, optarg);
				exit(1);
			}
			af_opt = optarg;
			break;

		case 'I':
			if (said_opt) {
				fprintf(stderr,
					"%s: Error, SAID parameter redefined:%s, already defined in SA:%s\n",
					progname, optarg, said_opt);
				exit(1);
			}
			if (proto_opt) {
				fprintf(stderr,
					"%s: Error, PROTO parameter redefined in SA:%s, already defined as:%s\n",
					progname, optarg, proto_opt);
				exit(1);
			}
			if (edst_opt) {
				fprintf(stderr,
					"%s: Error, EDST parameter redefined in SA:%s, already defined as:%s\n",
					progname, optarg, edst_opt);
				exit(1);
			}
			if (spi_opt) {
				fprintf(stderr,
					"%s: Error, SPI parameter redefined in SA:%s, already defined as:%s\n",
					progname, optarg, spi_opt);
				exit(1);
			}
			error_s = ttosa(optarg, 0, &said);
			if (error_s != NULL) {
				fprintf(stderr,
					"%s: Error, %s converting --sa argument:%s\n",
					progname, error_s, optarg);
				exit(1);
			}
			if (debug) {
				satot(&said, 0, ipsaid_txt,
				      sizeof(ipsaid_txt));
				fprintf(stdout, "%s: said=%s.\n",
					progname,
					ipsaid_txt);
			}
			/* init the src and dst with the same address family */
			if (address_family == 0) {
				address_family = addrtypeof(&said.dst);
			} else if (address_family != addrtypeof(&said.dst)) {
				fprintf(stderr,
					"%s: Error, specified address family (%d) is different that of SAID: %s\n",
					progname, address_family, optarg);
				exit(1);
			}
			anyaddr(address_family, &dst);
			anyaddr(address_family, &edst);
			anyaddr(address_family, &src);
			said_opt = optarg;
			break;

		case 'A':
			decode_blob(optarg, "Authentication Key", &authkey, &authkeylen);
			break;

		case 'E':
			decode_blob(optarg, "Encryption Key", &enckey, &enckeylen);
			break;

		case 'w':
		{
			err_t ugh = ttoul(optarg, 0, 0, &replay_window);

			if (ugh != NULL) {
				fprintf(stderr,
					"%s: Invalid replay_window parameter: %s\n",
					progname, ugh);
				exit(1);
			}
			if (!(1 <= replay_window && replay_window <= 64)) {
				fprintf(stderr,
					"%s: Failed -- Illegal window size: arg=%s, replay_window=%lu, must be 1 <= size <= 64.\n",
					progname, optarg, replay_window);
				exit(1);
			}
		}
			break;

		case 'i':
			decode_blob(optarg, "IV", &iv, &ivlen);
			break;

		case 'D':
			if (dst_opt) {
				fprintf(stderr,
					"%s: Error, DST parameter redefined:%s, already defined as:%s\n",
					progname, optarg, dst_opt);
				exit(1);
			}
			error_s = ttoaddr(optarg, 0, address_family, &dst);
			if (error_s != NULL) {
				fprintf(stderr,
					"%s: Error, %s converting --dst argument:%s\n",
					progname, error_s, optarg);
				exit(1);
			}
			dst_opt = optarg;
			if (debug) {
				ipstr_buf b;

				fprintf(stdout, "%s: dst=%s.\n",
					progname,
					ipstr(&dst, &b));
			}
			break;

		case 'F':  /* src port */
			{
				unsigned long u;
				err_t ugh = ttoulb(optarg, 0, 0, 0xFFFF, &u);

				if (ugh != NULL) {
					fprintf(stderr,
						"%s: Invalid source port parameter \"%s\": %s\n",
						progname, optarg, ugh);
					exit(1);
				}
				sport = u;
			}
			break;

		case 'G':  /* dst port */
			{
				unsigned long u;
				err_t ugh = ttoulb(optarg, 0, 0, 0xFFFF, &u);

				if (ugh != NULL) {
					fprintf(stderr,
						"%s: Invalid destination port parameter \"%s\": %s\n",
						progname, optarg, ugh);
					exit(1);
				}
				dport = u;
			}
			break;

		case 'N':  /* nat-type */
			if (strcaseeq(optarg, "nonesp")) {
				natt = ESPINUDP_WITH_NON_ESP;
			} else if (strcaseeq(optarg, "none")) {
				natt = 0;
			} else {
				/* ??? what does this do?  Where is it documented? */
				unsigned long u;
				err_t ugh = ttoulb(optarg, 0, 0, 0xFFFFFFFFul, &u);

				if (ugh != NULL) {
					fprintf(stderr,
						"%s: Invalid character in natt parameter \"%s\": %s\n",
						progname, optarg, ugh);
					exit(1);
				}
				natt = u;
			}
			break;

		case 'S':
			if (src_opt) {
				fprintf(stderr,
					"%s: Error, SRC parameter redefined:%s, already defined as:%s\n",
					progname, optarg, src_opt);
				exit(1);
			}
			error_s = ttoaddr(optarg, 0, address_family, &src);
			if (error_s != NULL) {
				fprintf(stderr,
					"%s: Error, %s converting --src argument:%s\n",
					progname, error_s, optarg);
				exit(1);
			}
			src_opt = optarg;
			if (debug) {
				ipstr_buf b;

				fprintf(stdout, "%s: src=%s.\n",
					progname,
					ipstr(&src, &b));
			}
			break;

		case 'h':
			usage(progname, stdout);
			exit(0);

		case '?':
			usage(progname, stderr);
			exit(1);

		case 'v':
			fprintf(stdout, "%s, %s\n", progname,
				ipsec_version_code());
			exit(1);

		case 'f':
			if (parse_life_options(life,
					       life_opt,
					       optarg) != 0)
				exit(1);
			break;

		default:
			fprintf(stderr,
				"%s: unrecognized option '%c', update option processing.\n",
				progname, c);
			exit(1);
		}
	}
	if (debug) {
		fprintf(stdout, "%s: All options processed.\n",
			progname);
	}

	if (stat("/proc/net/pfkey", &sts) == 0) {
		fprintf(stderr,
			"%s: NETKEY does not use the ipsec spi command. Use 'ip xfrm' instead.\n",
			progname);
		exit(1);
	}

	if (argcount == 1) {
		int ret = 1;

		if ((stat("/proc/net/ipsec_spi", &sts)) != 0) {
			fprintf(stderr,
				"%s: No spi - no IPsec support in kernel (are the modules loaded?)\n",
				progname);
		} else {
			ret = system("cat /proc/net/ipsec_spi");
			ret = ret != -1 &&
			      WIFEXITED(ret) ? WEXITSTATUS(ret) : 1;
		}
		exit(ret);
	}

	switch (alg) {
	case XF_OTHER_ALG:
		/* validate keysizes */
		if (proc_read_ok) {
			const struct sadb_alg *alg_p;
			size_t keylen, minbits, maxbits;
			alg_p = kernel_alg_sadb_alg_get(SADB_SATYPE_ESP,
							SADB_EXT_SUPPORTED_ENCRYPT,
							esp_info->encryptalg);
			assert(alg_p != NULL);
			keylen = enckeylen * 8;

			minbits = alg_p->sadb_alg_minbits;
			maxbits = alg_p->sadb_alg_maxbits;
			/*
			 * if explicit keylen told in encrypt algo, eg "aes128"
			 * check actual keylen "equality"
			 */
			if (esp_info->enckeylen &&
			    esp_info->enckeylen != keylen) {
				fprintf(stderr, "%s: invalid encryption keylen=%d, "
					"required %d by encrypt algo string=\"%s\"\n",
					progname,
					(int)keylen,
					(int)esp_info->enckeylen,
					alg_string);
				exit(1);

			}
			/* thanks DES for this sh*t */

			if (minbits > keylen || maxbits < keylen) {
				fprintf(stderr, "%s: invalid encryption keylen=%d, "
					"must be between %d and %d bits\n",
					progname,
					(int)keylen,
					(int)minbits,
					(int)maxbits);
				exit(1);
			}
			alg_p = kernel_alg_sadb_alg_get(SADB_SATYPE_ESP,
							SADB_EXT_SUPPORTED_AUTH,
							esp_info->authalg);
			assert(alg_p);
			keylen = authkeylen * 8;
			minbits = alg_p->sadb_alg_minbits;
			maxbits = alg_p->sadb_alg_maxbits;
			if (minbits > keylen || maxbits < keylen) {
				fprintf(stderr, "%s: invalid auth keylen=%d, "
					"must be between %d and %d bits\n",
					progname,
					(int)keylen,
					(int)minbits,
					(int)maxbits);
				exit(1);
			}
		}
		/*
		 * ??? this break was added in a2791fda77a5cfcc6bc992fbc5019f4448112f88
		 * It is likely correct, but we're not sure.
		 * Luckily this code is probably never used.
		 */
		break;
	case XF_IP4:
	case XF_IP6:
	case XF_DEL:
	case XF_COMPDEFLATE:
	case XF_COMPLZS:
		if (!said_opt) {
			if (isanyaddr(&edst)) {
				fprintf(stderr,
					"%s: SA destination not specified.\n",
					progname);
				exit(1);
			}
			if (!spi) {
				fprintf(stderr, "%s: SA SPI not specified.\n",
					progname);
				exit(1);
			}
			if (!proto) {
				fprintf(stderr,
					"%s: SA PROTO not specified.\n",
					progname);
				exit(1);
			}
			initsaid(&edst, htonl(spi), proto, &said);
		} else {
			proto = said.proto;
			spi = ntohl(said.spi);
			edst = said.dst;
		}
		if ((address_family != 0) &&
		    (address_family != addrtypeof(&said.dst))) {
			fprintf(stderr,
				"%s: Defined address family and address family of SA missmatch.\n",
				progname);
			exit(1);
		}

		if (debug) {
			fprintf(stdout, "%s: SA valid.\n",
				progname);
		}
		break;
	case XF_CLR:
		break;
	default:
		fprintf(stderr,
			"%s: No action chosen.  See '%s --help' for usage.\n",
			progname, progname);
		exit(1);
	}

	switch (alg) {
	case XF_CLR:
	case XF_DEL:
	case XF_IP4:
	case XF_IP6:
	case XF_COMPDEFLATE:
	case XF_COMPLZS:
	case XF_OTHER_ALG:
		break;
	default:
		fprintf(stderr,
			"%s: No action chosen.  See '%s --help' for usage.\n",
			progname, progname);
		exit(1);
	}
	if (debug) {
		fprintf(stdout, "%s: Algorithm ok.\n",
			progname);
	}

	pfkey_sock = pfkey_open_sock_with_error();
	if (pfkey_sock < 0)
		exit(1);

	/* Build an SADB_ADD message to send down. */
	/* It needs <base, SA, address(SD), key(AE)> minimum. */
	/*   Lifetime(HS) could be added before addresses. */
	pfkey_extensions_init(extensions);

	error = pfkey_msg_hdr_build(&extensions[0],
				    alg == XF_DEL ? SADB_DELETE :
					alg == XF_CLR ? SADB_FLUSH :
					SADB_ADD,
				    proto2satype(proto),
				    0,
				    ++pfkey_seq,
				    mypid);
	if (error != 0) {
		fprintf(stderr,
			"%s: Trouble building message header, error=%d.\n",
			progname, error);
		pfkey_extensions_free(extensions);
		exit(1);
	}

	switch (alg) {
	case XF_OTHER_ALG:
		authalg = esp_info->authalg;
		if (debug) {
			fprintf(stdout, "%s: debug: authalg=%d\n",
				progname, authalg);
		}
		break;
	default:
		authalg = SADB_AALG_NONE;
	}
	switch (alg) {
	case XF_COMPDEFLATE:
		encryptalg = SADB_X_CALG_DEFLATE;
		break;
	case XF_COMPLZS:
		encryptalg = SADB_X_CALG_LZS;
		break;
	case XF_OTHER_ALG:
		encryptalg = esp_info->encryptalg;
		if (debug) {
			fprintf(stdout, "%s: debug: encryptalg=%d\n",
				progname, encryptalg);
		}
		break;
	default:
		encryptalg = SADB_EALG_NONE;
	}
	/* IE: pfkey_msg->sadb_msg_type == SADB_FLUSH */
	if (!(alg == XF_CLR)) {
		sab.sa_base.sadb_sa_len        = 0;
		sab.sa_base.sadb_sa_exttype    = SADB_EXT_SA;
		sab.sa_base.sadb_sa_spi        = htonl(spi);
		sab.sa_base.sadb_sa_replay     = replay_window;
		sab.sa_base.sadb_sa_state      = K_SADB_SASTATE_MATURE;
		sab.sa_base.sadb_sa_auth       = authalg;
		sab.sa_base.sadb_sa_encrypt    = encryptalg;
		sab.sa_base.sadb_sa_flags      = 0;
		sab.sa_base.sadb_x_sa_ref      = IPSEC_SAREF_NULL;
		sab.sa_base.sadb_x_reserved[0] = 0;
		sab.sa_base.sadb_x_reserved[1] = 0;
		sab.sa_base.sadb_x_reserved[2] = 0;
		sab.sa_base.sadb_x_reserved[3] = 0;

		error = pfkey_sa_builds(&extensions[SADB_EXT_SA], sab);
		if (error != 0) {
			fprintf(stderr,
				"%s: Trouble building sa extension, error=%d.\n",
				progname, error);
			pfkey_extensions_free(extensions);
			exit(1);
		}

		if (saref_me || saref_him) {
			error = pfkey_saref_build(&extensions[
							  K_SADB_X_EXT_SAREF],
						  saref_me, saref_him);
			if (error) {
				fprintf(stderr,
					"%s: Trouble building saref extension, error=%d.\n",
					progname, error);
				pfkey_extensions_free(extensions);
				exit(1);
			}
		}

		if (outif != 0) {
			error = pfkey_outif_build(&extensions[
							   SADB_X_EXT_PLUMBIF],
						  outif);
			if (error != 0) {
				fprintf(stderr,
					"%s: Trouble building outif extension, error=%d.\n",
					progname, error);
				pfkey_extensions_free(extensions);
				exit(1);
			}
		}

		if (debug) {
			fprintf(stdout,
				"%s: extensions[0]=0p%p previously set with msg_hdr.\n",
				progname,
				extensions[0]);
		}
		if (debug) {
			fprintf(stdout,
				"%s: assembled SA extension, pfkey msg authalg=%d encalg=%d.\n",
				progname,
				authalg,
				encryptalg);
		}

		if (debug) {
			int i, j;

			for (i = 0; i < life_maxsever; i++) {
				for (j = 0; j < life_maxtype; j++) {
					fprintf(stdout,
						"%s: i=%d, j=%d, life_opt[%d][%d]=0p%p, life[%d][%d]=%d\n",
						progname,
						i, j, i, j, life_opt[i][j], i, j,
						life[i][j]);
				}
			}
		}

		emit_lifetime("lifetime_s", SADB_EXT_LIFETIME_SOFT, extensions, life_opt[life_soft], life[life_soft]);
		emit_lifetime("lifetime_h", SADB_EXT_LIFETIME_HARD, extensions, life_opt[life_hard], life[life_hard]);

		if (debug) {
			ipstr_buf b;

			fprintf(stdout,
				"%s: assembling address_s extension (%s).\n",
				progname, ipstr(&src, &b));
		}

		error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
					    SADB_EXT_ADDRESS_SRC,
					    0,
					    0,
					    sockaddrof(&src));
		if (error != 0) {
			ipstr_buf b;

			fprintf(stderr,
				"%s: Trouble building address_s extension (%s), error=%d.\n",
				progname, ipstr(&src, &b), error);
			pfkey_extensions_free(extensions);
			exit(1);
		}

		error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
					    SADB_EXT_ADDRESS_DST,
					    0,
					    0,
					    sockaddrof(&edst));
		if (error != 0) {
			ipstr_buf b;

			fprintf(stderr,
				"%s: Trouble building address_d extension (%s), error=%d.\n",
				progname, ipstr(&edst, &b), error);
			pfkey_extensions_free(extensions);
			exit(1);
		}

		switch (alg) {
		/*	Allow no auth ... after all is local root decision 8)  */
		case XF_OTHER_ALG:
			if (!authalg)
				break;
			error = pfkey_key_build(&extensions[SADB_EXT_KEY_AUTH],
						SADB_EXT_KEY_AUTH,
						authkeylen * 8,
						authkey);
			if (error != 0) {
				fprintf(stderr,
					"%s: Trouble building key_a extension, error=%d.\n",
					progname, error);
				pfkey_extensions_free(extensions);
				exit(1);
			}
			if (debug) {
				fprintf(stdout,
					"%s: key_a extension assembled.\n",
					progname);
			}
			break;
		default:
			break;
		}

		switch (alg) {
		case XF_OTHER_ALG:
			if (enckeylen == 0) {
				if (debug)
					fprintf(stdout, "%s: key not provided (NULL alg?).\n",
						progname);
				break;

			}
			error = pfkey_key_build(&extensions[SADB_EXT_KEY_ENCRYPT],
						SADB_EXT_KEY_ENCRYPT,
						enckeylen * 8,
						enckey);
			if (error != 0) {
				fprintf(stderr,
					"%s: Trouble building key_e extension, error=%d.\n",
					progname, error);
				pfkey_extensions_free(extensions);
				exit(1);
			}
			if (debug) {
				fprintf(stdout,
					"%s: key_e extension assembled.\n",
					progname);
			}
			break;
		default:
			break;
		}

	}

	if (natt != 0) {
		bool success;

		int err;

		err = pfkey_x_nat_t_type_build(&extensions[
							 K_SADB_X_EXT_NAT_T_TYPE],
					       natt);
		success = pfkey_build(err,
				      "pfkey_nat_t_type Add ESP SA",
				      ipsaid_txt, extensions);
		if (!success)
			return FALSE;

		if (debug)
			fprintf(stderr, "setting natt_type to %d\n", natt);

		if (sport != 0) {
			err = pfkey_x_nat_t_port_build(
					&extensions[K_SADB_X_EXT_NAT_T_SPORT],
					K_SADB_X_EXT_NAT_T_SPORT,
					sport);
			success = pfkey_build(err,
					      "pfkey_nat_t_sport Add ESP SA",
					      ipsaid_txt, extensions);
			if (debug)
				fprintf(stderr, "setting natt_sport to %d\n",
					sport);
			if (!success)
				return FALSE;
		}

		if (dport != 0) {
			err = pfkey_x_nat_t_port_build(
					&extensions[K_SADB_X_EXT_NAT_T_DPORT],
					K_SADB_X_EXT_NAT_T_DPORT,
					dport);
			success = pfkey_build(err,
					      "pfkey_nat_t_dport Add ESP SA",
					      ipsaid_txt, extensions);
			if (debug)
				fprintf(stderr, "setting natt_dport to %d\n",
					dport);
			if (!success)
				return FALSE;
		}

#if 0
		/* not yet implemented */
		if (natt != 0 && !isanyaddr(&natt_oa)) {
			ip_str_buf b;

			success = pfkeyext_address(SADB_X_EXT_NAT_T_OA,
						   &natt_oa,
						   "pfkey_nat_t_oa Add ESP SA",
						   ipsaid_txt, extensions);
			if (debug)
				fprintf(stderr, "setting nat_oa to %s\n",
					ipstr(&natt_oa, &b));
			if (!success)
				return FALSE;
		}
#endif
	}

	if (debug) {
		fprintf(stdout, "%s: assembling pfkey msg....\n",
			progname);
	}
	error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN);
	if (error != 0) {
		fprintf(stderr,
			"%s: Trouble building pfkey message, error=%d.\n",
			progname, error);
		pfkey_extensions_free(extensions);
		pfkey_msg_free(&pfkey_msg);
		exit(1);
	}
	if (debug) {
		fprintf(stdout, "%s: assembled.\n",
			progname);
	}
	if (debug) {
		fprintf(stdout, "%s: writing pfkey msg.\n",
			progname);
	}
	io_error = write(pfkey_sock,
			 pfkey_msg,
			 pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
	if (io_error < 0) {
		fprintf(stderr, "%s: pfkey write failed (errno=%d): ",
			progname, errno);
		pfkey_extensions_free(extensions);
		pfkey_msg_free(&pfkey_msg);
		switch (errno) {
		case EACCES:
			fprintf(stderr, "access denied.  ");
			if (getuid() == 0)
				fprintf(stderr,
					"Check permissions.  Should be 600.\n");


			else
				fprintf(stderr,
					"You must be root to open this file.\n");


			break;
		case EUNATCH:
			fprintf(stderr,
				"Netlink not enabled OR KLIPS not loaded.\n");
			break;
		case EBUSY:
			fprintf(stderr,
				"KLIPS is busy.  Most likely a serious internal error occured in a previous command.  Please report as much detail as possible to development team.\n");
			break;
		case EINVAL:
			fprintf(stderr,
				"Invalid argument, check kernel log messages for specifics.\n");
			break;
		case ENODEV:
			fprintf(stderr, "KLIPS not loaded or enabled.\n");
			fprintf(stderr, "No device?!?\n");
			break;
		case ENOBUFS:
			fprintf(stderr, "No kernel memory to allocate SA.\n");
			break;
		case ESOCKTNOSUPPORT:
			fprintf(stderr,
				"Algorithm support not available in the kernel.  Please compile in support.\n");
			break;
		case EEXIST:
			fprintf(stderr,
				"SA already in use.  Delete old one first.\n");
			break;
		case ENOENT:
			fprintf(stderr,
				"device does not exist.  See Libreswan installation procedure.\n");
			break;
		case ENXIO:
		case ESRCH:
			fprintf(stderr,
				"SA does not exist.  Cannot delete.\n");
			break;
		case ENOSPC:
			fprintf(stderr,
				"no room in kernel SAref table.  Cannot process request.\n");
			break;
		case ESPIPE:
			fprintf(stderr,
				"kernel SAref table internal error.  Cannot process request.\n");
			break;
		default:
			fprintf(stderr,
				"Unknown socket write error %d (%s).  Please report as much detail as possible to development team.\n",
				errno, strerror(errno));
		}
		exit(1);
	} else if (io_error !=
		   (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) {
		fprintf(stderr, "%s: pfkey write truncated to %d bytes\n",
			progname, (int)io_error);
		pfkey_extensions_free(extensions);
		pfkey_msg_free(&pfkey_msg);
		exit(1);
	}

	if (debug) {
		fprintf(stdout, "%s: pfkey command written to socket.\n",
			progname);
	}

	if (pfkey_msg != NULL) {
		pfkey_extensions_free(extensions);
		pfkey_msg_free(&pfkey_msg);
	}
	if (debug) {
		fprintf(stdout, "%s: pfkey message buffer freed.\n",
			progname);
	}
	if (authkey != NULL) {
		memset(authkey, 0, authkeylen);
		free(authkey);
	}
	if (enckey != NULL) {
		memset(enckey, 0, enckeylen);
		free(enckey);
	}
	if (iv != NULL) {
		memset(iv, 0, ivlen);
		free(iv);
	}

	if (listenreply || saref_me || dumpsaref) {
		ssize_t readlen;
		unsigned char pfkey_buf[PFKEYv2_MAX_MSGSIZE];

		while ((readlen = read(pfkey_sock, pfkey_buf,
				     sizeof(pfkey_buf))) > 0) {
			struct sadb_ext *extensions[K_SADB_EXT_MAX + 1];
			pfkey_extensions_init(extensions);
			pfkey_msg = (struct sadb_msg *)pfkey_buf;

			/* first, see if we got enough for an sadb_msg */
			if ((size_t)readlen < sizeof(struct sadb_msg)) {
				if (debug) {
					printf("%s: runt packet of size: %ld (<%lu)\n",
						progname, (long)readlen,
						(unsigned long)sizeof(struct
								      sadb_msg));
				}
				continue;
			}

			/* okay, we got enough for a message, print it out */
			if (debug) {
				printf("%s: pfkey v%d msg received. type=%d(%s) seq=%d len=%d pid=%d errno=%d satype=%d(%s)\n",
					progname,
					pfkey_msg->sadb_msg_version,
					pfkey_msg->sadb_msg_type,
					pfkey_v2_sadb_type_string(pfkey_msg->
								  sadb_msg_type),
					pfkey_msg->sadb_msg_seq,
					pfkey_msg->sadb_msg_len,
					pfkey_msg->sadb_msg_pid,
					pfkey_msg->sadb_msg_errno,
					pfkey_msg->sadb_msg_satype,
					satype2name(pfkey_msg->sadb_msg_satype));
			}

			if (readlen !=
			    (ssize_t)(pfkey_msg->sadb_msg_len *
				      IPSEC_PFKEYv2_ALIGN)) {
				if (debug) {
					printf("%s: packet size read from socket=%d doesn't equal sadb_msg_len %u * %u; message not decoded\n",
						progname,
						(int)readlen,
						(unsigned)pfkey_msg->sadb_msg_len,
						(unsigned)IPSEC_PFKEYv2_ALIGN);
				}
				continue;
			}

			if (pfkey_msg_parse(pfkey_msg, NULL, extensions,
					    EXT_BITS_OUT)) {
				if (debug) {
					printf("%s: unparseable PF_KEY message.\n",
						progname);
				}
				continue;
			}

			if (debug) {
				printf("%s: parseable PF_KEY message.\n",
					progname);
			}
			if ((pid_t)pfkey_msg->sadb_msg_pid == mypid) {
				if (saref_me || dumpsaref) {
					struct sadb_x_saref *s =
						(struct sadb_x_saref *)
						extensions[
							K_SADB_X_EXT_SAREF];

					if (s != NULL) {
						printf("%s: saref=%d/%d\n",
						       progname,
						       s->sadb_x_saref_me,
						       s->sadb_x_saref_him);
					}
				}
				break;
			}
		}
	}
	(void) close(pfkey_sock);  /* close the socket */
	if (debug || listenreply)
		printf("%s: exited normally\n", progname);
	exit(0);
}