Пример #1
0
void pfkey_register(uint8_t satype)
{
	/* for registering SA types that can be negotiated */
	int error = 0;
	struct sadb_ext *extensions[K_SADB_EXT_MAX + 1];
	struct sadb_msg *pfkey_msg;

	pfkey_extensions_init(extensions);
	if ((error = pfkey_msg_hdr_build(&extensions[0],
					 SADB_REGISTER,
					 satype,
					 0,
					 ++pfkey_seq,
					 getpid()))) {
		fprintf(stderr,
			"%s: Trouble building message header, error=%d.\n",
			progname, 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 (write(pfkey_sock, pfkey_msg,
		  pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) !=
	    (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) {
		/* cleanup code here */
		fprintf(stderr, "%s: Trouble writing to channel PF_KEY.\n",
			progname);
		pfkey_extensions_free(extensions);
		pfkey_msg_free(&pfkey_msg);
		exit(1);
	}
	pfkey_extensions_free(extensions);
	pfkey_msg_free(&pfkey_msg);
}
Пример #2
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);
}
int sadb_msg_add_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
{
	int error = 0;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
	struct sadb_sa *sa;
	struct sadb_address *src;
	struct sadb_address *dst;
	struct ipsec_sa *sa_entry = NULL;

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");
		error = -EINVAL;
		goto rtn;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));
	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
	error = sadb_msg_detect_ext(msg, ext_msgs);

	if (ext_msgs[SADB_EXT_SA] &&
		ext_msgs[SADB_EXT_ADDRESS_SRC] &&
		ext_msgs[SADB_EXT_ADDRESS_DST])
	{
		sa  = (struct sadb_sa*)ext_msgs[SADB_EXT_SA];

		if ( ((!sa->sadb_sa_auth && !sa->sadb_sa_encrypt) && msg->sadb_msg_satype != SADB_X_SATYPE_COMP) || 
				sa->sadb_sa_auth > SADB_AALG_MAX || 
				sa->sadb_sa_encrypt > SADB_EALG_MAX ) {
			PFKEY_DEBUG("sa has no transform or invalid transform value\n");
			error = -EINVAL;
			goto rtn;
		}

		switch (msg->sadb_msg_satype) {

		case SADB_SATYPE_AH:
		case SADB_SATYPE_ESP:
		case SADB_X_SATYPE_COMP:
			break;
		case SADB_SATYPE_RSVP:
		case SADB_SATYPE_OSPFV2:
		case SADB_SATYPE_RIPV2:
		case SADB_SATYPE_MIP:
		default:
			PFKEY_DEBUG("invalid sa type\n");
			error = -EINVAL;
			goto rtn;
		}

		if (msg->sadb_msg_satype == SADB_SATYPE_ESP && !(sa->sadb_sa_encrypt)) {
			PFKEY_DEBUG("sa type is esp but no algorithm\n");
			error = -EINVAL;
			goto rtn;
		}

		sa_entry = ipsec_sa_kmalloc();
		if (!sa_entry) {
			PFKEY_DEBUG("sa_entry: null\n");
			error = -ENOMEM;
			goto err;
		}

		src = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_SRC];
		dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];

		sa_entry->ipsec_proto = msg->sadb_msg_satype;

		/* SPI which is under 255 is reserved by IANA. 
		 * Additionally, 256 and 257 reserved for our internal use.  */
		if (ntohl(sa->sadb_sa_spi) < 258 && sa_entry->ipsec_proto != SADB_X_SATYPE_COMP) {
			PFKEY_DEBUG("SPI value is reserved.(SPI<258)\n");
			goto err;
		}

		sa_entry->spi = sa->sadb_sa_spi;

		error = sadb_address_to_sockaddr( src,
				(struct sockaddr*)&sa_entry->src);
		if (error) {
			PFKEY_DEBUG("src translation failed\n");
			goto err;
		}
		error = sadb_address_to_sockaddr( dst,
				(struct sockaddr*)&sa_entry->dst);
		if (error) {
			PFKEY_DEBUG("dst translation failed\n");
			goto err;
		}

		if (src->sadb_address_proto == dst->sadb_address_proto) {
			sa_entry->proto = src->sadb_address_proto;
		} else {
			error = -EINVAL;
			goto err;
		} 

		sa_entry->prefixlen_s = src->sadb_address_prefixlen;
		sa_entry->prefixlen_d = dst->sadb_address_prefixlen;

		if (sa->sadb_sa_auth) {
			if( (ext_msgs[SADB_EXT_KEY_AUTH]) ) {
				error = sadb_key_to_auth(sa->sadb_sa_auth,
					(struct sadb_key*) ext_msgs[SADB_EXT_KEY_AUTH], sa_entry);
				if (error)
					goto err;
			} else {
				PFKEY_DEBUG("SA has auth algo but there is no key for auth\n");
				error = -EINVAL;
				goto err;
			}
		}

		if (sa->sadb_sa_encrypt) {
			if (sa->sadb_sa_encrypt == SADB_EALG_NULL && 
					sa->sadb_sa_auth == SADB_AALG_NONE) {
				error = -EINVAL;
				goto err;
			}
			if (msg->sadb_msg_satype != SADB_X_SATYPE_COMP) {
				error = sadb_key_to_esp(sa->sadb_sa_encrypt, 
					(struct sadb_key*) ext_msgs[SADB_EXT_KEY_ENCRYPT], sa_entry);
				if (error)
					goto err;
			}
		}

		if (ext_msgs[SADB_EXT_ADDRESS_PROXY]) {
			printk(KERN_WARNING "PFKEY proxy translation is not supported.\n");
			goto err;
		}

		if (ext_msgs[SADB_EXT_LIFETIME_HARD]) {
			error = sadb_lifetime_to_lifetime((struct sadb_lifetime*)ext_msgs[SADB_EXT_LIFETIME_HARD],
						&sa_entry->lifetime_h);
			if (error) goto err;
		}

		if (ext_msgs[SADB_EXT_LIFETIME_SOFT]) {
			error = sadb_lifetime_to_lifetime((struct sadb_lifetime*)ext_msgs[SADB_EXT_LIFETIME_SOFT],
						&sa_entry->lifetime_s);
			if (error) goto err;
		}

		sa_entry->state = SADB_SASTATE_MATURE;

		error = sadb_append(sa_entry);	
		if (error) goto err;	

		reply_ext_msgs[0] = (struct sadb_ext*) msg;
		reply_ext_msgs[SADB_EXT_SA] = ext_msgs[SADB_EXT_SA];
		reply_ext_msgs[SADB_EXT_ADDRESS_SRC] = ext_msgs[SADB_EXT_ADDRESS_SRC];
		reply_ext_msgs[SADB_EXT_ADDRESS_DST] = ext_msgs[SADB_EXT_ADDRESS_DST];

		if (ext_msgs[SADB_EXT_LIFETIME_HARD])
			reply_ext_msgs[SADB_EXT_LIFETIME_HARD] = ext_msgs[SADB_EXT_LIFETIME_HARD];

		if (ext_msgs[SADB_EXT_LIFETIME_SOFT])
			reply_ext_msgs[SADB_EXT_LIFETIME_SOFT] = ext_msgs[SADB_EXT_LIFETIME_SOFT];

		error = pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
		goto rtn;
	} else {
		PFKEY_DEBUG("extensions not enough\n");
		error = -EINVAL;
		goto err;
	}

err:
	ipsec_sa_kfree(sa_entry);
rtn:
	return error;
}
Пример #4
0
int sadb_msg_send_acquire(struct ipsec_sa *sa)
{
	int i=0, error = 0;
	uint  comb_num = 0;
	struct sadb_comb combs[4];
	struct digest_implementation *di = NULL;
	struct cipher_implementation *ci = NULL;
	struct sadb_msg *msg = NULL;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
	struct socket_list *pfkey_socketsp = NULL;

	memset(ext_msgs, 0, sizeof(ext_msgs));
	memset(combs, 0, sizeof(combs));

	if (sa->ipsec_proto == SADB_SATYPE_AH || sa->ipsec_proto == SADB_SATYPE_ESP) {
		di = find_digest_by_name("md5", 0 /* atomic */);
		if (di) {
			combs[comb_num].sadb_comb_auth = SADB_AALG_MD5HMAC;
			combs[comb_num].sadb_comb_auth_minbits = AUTH_MD5HMAC_KEY_BITS;
			combs[comb_num].sadb_comb_auth_maxbits = AUTH_MD5HMAC_KEY_BITS;
			combs[comb_num].sadb_comb_reserved = 0;
			combs[comb_num].sadb_comb_soft_allocations = 0;
			combs[comb_num].sadb_comb_hard_allocations = 0;
			combs[comb_num].sadb_comb_soft_bytes = 0;
			combs[comb_num].sadb_comb_hard_bytes = 0;
			combs[comb_num].sadb_comb_soft_addtime = 57600;
			combs[comb_num].sadb_comb_hard_addtime = 86400;
			combs[comb_num].sadb_comb_soft_usetime = 57600;
			combs[comb_num].sadb_comb_hard_usetime = 86400;
			comb_num++;
			di = NULL;	
		}
	
		di = find_digest_by_name("sha1", 0 /* atomic */);
		if (di) {
			combs[comb_num].sadb_comb_auth = SADB_AALG_SHA1HMAC;
			combs[comb_num].sadb_comb_auth_minbits = AUTH_SHA1HMAC_KEY_BITS;
			combs[comb_num].sadb_comb_auth_maxbits = AUTH_SHA1HMAC_KEY_BITS;
			combs[comb_num].sadb_comb_reserved = 0;
			combs[comb_num].sadb_comb_soft_allocations = 0;
			combs[comb_num].sadb_comb_hard_allocations = 0;
			combs[comb_num].sadb_comb_soft_bytes = 0;
			combs[comb_num].sadb_comb_hard_bytes = 0;
			combs[comb_num].sadb_comb_soft_addtime = 57600;
			combs[comb_num].sadb_comb_hard_addtime = 86400;
			combs[comb_num].sadb_comb_soft_usetime = 57600;
			combs[comb_num].sadb_comb_hard_usetime = 86400;
			comb_num++;
			di = NULL;
		}
	}

	if (sa->ipsec_proto == SADB_SATYPE_ESP) {
		ci = find_cipher_by_name("des-cbc", 1 /* atomic */);
		if (ci) {
			combs[comb_num].sadb_comb_encrypt = SADB_EALG_DESCBC;
			combs[comb_num].sadb_comb_encrypt_minbits = ESP_DES_KEY_BITS;
			combs[comb_num].sadb_comb_encrypt_maxbits = ESP_DES_KEY_BITS;
			combs[comb_num].sadb_comb_reserved = 0;
			combs[comb_num].sadb_comb_soft_allocations = 0;
			combs[comb_num].sadb_comb_hard_allocations = 0;
			combs[comb_num].sadb_comb_soft_bytes = 0;
			combs[comb_num].sadb_comb_hard_bytes = 0;
			combs[comb_num].sadb_comb_soft_addtime = 57600;
			combs[comb_num].sadb_comb_hard_addtime = 86400;
			combs[comb_num].sadb_comb_soft_usetime = 57600;
			combs[comb_num].sadb_comb_hard_usetime = 86400;
			comb_num++;
			ci = NULL;
		}

		ci = find_cipher_by_name("des_ede3-cbc", 1 /* atomic */);
		if (ci) {
			combs[comb_num].sadb_comb_encrypt = SADB_EALG_3DESCBC;
			combs[comb_num].sadb_comb_encrypt_minbits = ESP_3DES_KEY_BITS;
			combs[comb_num].sadb_comb_encrypt_maxbits = ESP_3DES_KEY_BITS;
			combs[comb_num].sadb_comb_reserved = 0;
			combs[comb_num].sadb_comb_soft_allocations = 0;
			combs[comb_num].sadb_comb_hard_allocations = 0;
			combs[comb_num].sadb_comb_soft_bytes = 0;
			combs[comb_num].sadb_comb_hard_bytes = 0;
			combs[comb_num].sadb_comb_soft_addtime = 57600;
			combs[comb_num].sadb_comb_hard_addtime = 86400;
			combs[comb_num].sadb_comb_soft_usetime = 57600;
			combs[comb_num].sadb_comb_hard_usetime = 86400;
			comb_num++;
			ci = NULL;
		}

		ci = find_cipher_by_name("aes-cbc", 1 /* atomic */);
		if (ci) {
			combs[comb_num].sadb_comb_encrypt = SADB_EALG_AES;
			combs[comb_num].sadb_comb_encrypt_minbits = ESP_AES_KEY_BITS;
			combs[comb_num].sadb_comb_encrypt_maxbits = ESP_AES_KEY_BITS;
			combs[comb_num].sadb_comb_reserved = 0;
			combs[comb_num].sadb_comb_soft_allocations = 0;
			combs[comb_num].sadb_comb_hard_allocations = 0;
			combs[comb_num].sadb_comb_soft_bytes = 0;
			combs[comb_num].sadb_comb_hard_bytes = 0;
			combs[comb_num].sadb_comb_soft_addtime = 57600;
			combs[comb_num].sadb_comb_hard_addtime = 86400;
			combs[comb_num].sadb_comb_soft_usetime = 57600;
			combs[comb_num].sadb_comb_hard_usetime = 86400;
			comb_num++;
			ci = NULL;
		}
	}

	error = pfkey_msg_hdr_build(&ext_msgs[0],
				    SADB_ACQUIRE,
				    sa->ipsec_proto,
				    0,
				    0,
				    0);
	if (error) {
		PFKEY_DEBUG("pfkey_msg_hdr_build is failed\n");
		goto free_ext_finish;
	}

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
					SADB_EXT_ADDRESS_SRC,
					sa->proto,
					sa->prefixlen_s,
					(struct sockaddr*)&sa->src);
	if (error) goto free_ext_finish;

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
					SADB_EXT_ADDRESS_DST,
					sa->proto,
					sa->prefixlen_d,
					(struct sockaddr*)&sa->dst);
	if (error) goto free_ext_finish;

	error = pfkey_prop_build(&ext_msgs[SADB_EXT_PROPOSAL],
					64,
					comb_num,
					combs);
	if (error) goto free_ext_finish;


	error = pfkey_msg_build(&msg, ext_msgs, EXT_BITS_OUT);

	write_lock(&pfkey_sk_lock);
	for (pfkey_socketsp = pfkey_registered_sockets[sa->ipsec_proto];
		pfkey_socketsp;
			pfkey_socketsp = pfkey_socketsp->next)
	{
		pfkey_upmsg(pfkey_socketsp->socketp, msg);
	}
	write_unlock(&pfkey_sk_lock);

	kfree(msg);
free_ext_finish:

	for(i=0; i<SADB_MAX+1; i++) {
		if (ext_msgs[i]) {
			kfree(ext_msgs[i]);
		}
	}

	return 0;
}
Пример #5
0
int sadb_msg_register_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
{
	int error = 0;
	uint  alg_num = 0;
	struct sadb_alg algs[5];
	struct digest_implementation *di = NULL;
	struct cipher_implementation *ci = NULL;
	struct sadb_ext *reply_ext_msgs[SADB_EXT_MAX+1];

	if (!(sk&&msg)) {
		PFKEY_DEBUG("msg or sk is null\n");
		error = -EINVAL;
		PFKEY_DEBUG("msg or *reply is null\n");
		goto err; 	
	}

	error = sadb_msg_sanity_check(msg);
	if (error) {
		goto err;
	}

	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
	memset(algs, 0, sizeof(algs));

	switch (msg->sadb_msg_satype) {

	case SADB_SATYPE_AH:
	case SADB_SATYPE_ESP:
		break;
	case SADB_SATYPE_RSVP:
	case SADB_SATYPE_OSPFV2:
	case SADB_SATYPE_RIPV2:
	case SADB_SATYPE_MIP:
	case SADB_X_SATYPE_IPIP:
	case SADB_X_SATYPE_COMP:
	case SADB_X_SATYPE_INT:

	default:
		error = -EINVAL;
		goto err;
	}

	write_lock(&pfkey_sk_lock);
	/*
	 register a socket with the proper SA type's socket list
	 it will be release in pfkey_release process (file:pfkey_v2.c).
	*/
	error = pfkey_list_insert_socket(sk->socket, &pfkey_registered_sockets[msg->sadb_msg_satype]);
	if (error) {
		goto err;
	}
	write_unlock(&pfkey_sk_lock);

	PFKEY_DEBUG("socket=%p registered, SA type is %d\n", sk->socket, msg->sadb_msg_satype);

	reply_ext_msgs[0] = (struct sadb_ext*)msg;

	if (msg->sadb_msg_satype == SADB_SATYPE_AH || msg->sadb_msg_satype == SADB_SATYPE_ESP) {
		di = find_digest_by_name("md5", 0 /* atomic */);
		if (di) {
			algs[alg_num].sadb_alg_id = SADB_AALG_MD5HMAC;
			algs[alg_num].sadb_alg_ivlen = 0;
			algs[alg_num].sadb_alg_minbits = AUTH_MD5HMAC_KEY_BITS;
			algs[alg_num].sadb_alg_maxbits = AUTH_MD5HMAC_KEY_BITS;
			algs[alg_num].sadb_alg_reserved = 0;
			alg_num++;
			di = NULL;	
		}
	
		di = find_digest_by_name("sha1", 0 /* atomic */);
		if (di) {
			algs[alg_num].sadb_alg_id = SADB_AALG_SHA1HMAC;
			algs[alg_num].sadb_alg_ivlen = 0;
			algs[alg_num].sadb_alg_minbits = AUTH_SHA1HMAC_KEY_BITS;
			algs[alg_num].sadb_alg_maxbits = AUTH_SHA1HMAC_KEY_BITS;
			algs[alg_num].sadb_alg_reserved = 0;
			alg_num++;
			di = NULL;
		}

		if (msg->sadb_msg_satype == SADB_SATYPE_AH) {
			error = pfkey_supported_build(&reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH],
						SADB_EXT_SUPPORTED_AUTH,
						alg_num,
						algs);
			if (error) goto free_ext_finish;
		}

	}

	if (msg->sadb_msg_satype == SADB_SATYPE_ESP) {
		ci = find_cipher_by_name("des-cbc", 1 /* atomic */);
		if (ci) {
			ci->lock();
			algs[alg_num].sadb_alg_id = SADB_EALG_DESCBC;
			algs[alg_num].sadb_alg_ivlen = ci->ivsize;
			algs[alg_num].sadb_alg_minbits = ESP_DES_KEY_BITS;
			algs[alg_num].sadb_alg_maxbits = ESP_DES_KEY_BITS;
			algs[alg_num].sadb_alg_reserved = 0;
			alg_num++;
			ci->unlock();
			ci = NULL;
		}

		ci = find_cipher_by_name("des_ede3-cbc", 1 /* atomic */);
		if (ci) {
			ci->lock();
			algs[alg_num].sadb_alg_id = SADB_EALG_3DESCBC;
			algs[alg_num].sadb_alg_ivlen = ci->ivsize;
			algs[alg_num].sadb_alg_minbits = ESP_3DES_KEY_BITS;
			algs[alg_num].sadb_alg_maxbits = ESP_3DES_KEY_BITS;
			algs[alg_num].sadb_alg_reserved = 0;
			alg_num++;
			ci->unlock();
			ci = NULL;
		}
		ci = find_cipher_by_name("aes-cbc", 1 /* atomic */);
		if (ci) {
			ci->lock();
			algs[alg_num].sadb_alg_id = SADB_EALG_AES;
			algs[alg_num].sadb_alg_ivlen = ci->ivsize;
			algs[alg_num].sadb_alg_minbits = ESP_AES_KEY_BITS;
			algs[alg_num].sadb_alg_maxbits = ESP_AES_KEY_BITS;
			algs[alg_num].sadb_alg_reserved = 0;
			alg_num++;
			ci->unlock();
			ci = NULL;
		}

		error = pfkey_supported_build(&reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT],
						SADB_EXT_SUPPORTED_ENCRYPT,
						alg_num,
						algs);
		if (error) goto free_ext_finish;

	}

	pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);

free_ext_finish:

	if (reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH])
		kfree(reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH]);

	if (reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT])
		kfree(reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT]);


err:

	return error;
}
Пример #6
0
int sadb_msg_send_expire(struct ipsec_sa *sa)
{
	int i=0, error = 0;
	struct sadb_msg *msg = NULL;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
	struct socket_list *pfkey_socketsp = NULL;

	if (!sa) {
		PFKEY_DEBUG("sa is null\n");
		return -EINVAL;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));

	error = pfkey_msg_hdr_build(&ext_msgs[0],
				    SADB_EXPIRE,
				    sa->ipsec_proto,
				    0,
				    0,
				    0);
	if (error) {
		PFKEY_DEBUG("pfkey_msg_hdr_build is failed\n");
		goto free_ext_finish;
	}

	error = pfkey_sa_build(&ext_msgs[SADB_EXT_SA],
				   SADB_EXT_SA,
				   sa->spi,
				   64,
				   sa->state,
				   sa->auth_algo.algo,
				   sa->esp_algo.algo,
				   0); /* TODO: add pfs flag to struct ipsec_sa */
	if (error) {
		PFKEY_DEBUG("pfkey_sa_build is failed\n");
		goto free_ext_finish;
	}

	error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_CURRENT],
					 SADB_EXT_LIFETIME_CURRENT,
					 sa->lifetime_c.allocations,
					 sa->lifetime_c.bytes,
					 sa->lifetime_c.addtime,
					 sa->lifetime_c.usetime);
	if (error) {
		PFKEY_DEBUG("pfkey_lifetime_build is failed\n");
		goto free_ext_finish;
	}

	switch(sa->state) {
	case SADB_SASTATE_DEAD:
		error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_HARD],
						 SADB_EXT_LIFETIME_HARD,
						 sa->lifetime_h.allocations,
						 sa->lifetime_h.bytes,
						 sa->lifetime_h.addtime,
						 sa->lifetime_h.usetime);
		if (error) {
			PFKEY_DEBUG("pfkey_liftime_build(hard) is failed\n");
			goto free_ext_finish;
		}
		break;

	case SADB_SASTATE_DYING:
		error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_SOFT],
						 SADB_EXT_LIFETIME_SOFT,
						 sa->lifetime_s.allocations,
						 sa->lifetime_s.bytes,
						 sa->lifetime_s.addtime,
						 sa->lifetime_s.usetime);
		if (error) {
			PFKEY_DEBUG("pfkey_lifetime_build(soft) is failed\n");
			goto free_ext_finish;
		}
		break;

	case SADB_SASTATE_LARVAL:
	case SADB_SASTATE_MATURE:
	default:
		error = -EINVAL;
		goto free_ext_finish;

	}
	
	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
					SADB_EXT_ADDRESS_SRC,
					sa->proto,
					sa->prefixlen_s,
					(struct sockaddr*)&sa->src);
	if (error) goto free_ext_finish;

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
					SADB_EXT_ADDRESS_DST,
					sa->proto,
					sa->prefixlen_d,
					(struct sockaddr*)&sa->dst);
	if (error) goto free_ext_finish;

	error = pfkey_msg_build(&msg, ext_msgs, EXT_BITS_OUT);

	write_lock(&pfkey_sk_lock);
	for (pfkey_socketsp = pfkey_open_sockets;
		pfkey_socketsp;
			pfkey_socketsp = pfkey_socketsp->next)
	{
		pfkey_upmsg(pfkey_socketsp->socketp, msg);
	}
	write_unlock(&pfkey_sk_lock);

	kfree(msg);

free_ext_finish:
	for(i=0; i<SADB_MAX+1; i++) {
		if (ext_msgs[i]) {
			kfree(ext_msgs[i]);
		}
	}

	return 0;

}
Пример #7
0
/* Finish (building, sending, accepting response for) PF_KEY message.
 * If response isn't NULL, the response from the kernel will be
 * placed there (and its errno field will not be examined).
 * Returns TRUE iff all appears well.
 */
static bool
finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1]
, const char *description
, const char *text_said
, pfkey_buf *response)
{
    struct sadb_msg *pfkey_msg;
    bool success = TRUE;
    int error;

    error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN);

    if (error != 0)
    {
	loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d"
	    , description, text_said, error);
	success = FALSE;
    }
    else
    {
	size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN;

	DBG(DBG_KLIPS,
	    DBG_log("finish_pfkey_msg: %s message %u for %s %s"
		, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
		, pfkey_msg->sadb_msg_seq
		, description, text_said);
	    DBG_dump(NULL, (void *) pfkey_msg, len));

	if (!no_klips)
	{
	    ssize_t r = write(pfkeyfd, pfkey_msg, len);

	    if (r != (ssize_t)len)
	    {
		if (r < 0)
		{
		    log_errno((e
			, "pfkey write() of %s message %u"
			  " for %s %s failed"
			, sparse_val_show(pfkey_type_names
			    , pfkey_msg->sadb_msg_type)
			, pfkey_msg->sadb_msg_seq
			, description, text_said));
		}
		else
		{
		    loglog(RC_LOG_SERIOUS
			, "ERROR: pfkey write() of %s message %u"
			  " for %s %s truncated: %ld instead of %ld"
			, sparse_val_show(pfkey_type_names
			    , pfkey_msg->sadb_msg_type)
			, pfkey_msg->sadb_msg_seq
			, description, text_said
			, (long)r, (long)len);
		}
		success = FALSE;

		/* if we were compiled with debugging, but we haven't already
		 * dumped the KLIPS command, do so.
		 */
#ifdef DEBUG
		if ((cur_debugging & DBG_KLIPS) == 0)
		    DBG_dump(NULL, (void *) pfkey_msg, len);
#endif
	    }
	    else
	    {
		/* Check response from KLIPS.
		 * It ought to be an echo, perhaps with additional info.
		 * If the caller wants it, response will point to space.
		 */
		pfkey_buf b;
		pfkey_buf *bp = response != NULL? response : &b;

		if (!pfkey_get_response(bp, ((struct sadb_msg *) extensions[0])->sadb_msg_seq))
		{
		    loglog(RC_LOG_SERIOUS
			, "ERROR: no response to our PF_KEY %s message for %s %s"
			, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
			, description, text_said);
		    success = FALSE;
		}
		else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type)
		{
		    loglog(RC_LOG_SERIOUS
			, "FreeS/WAN ERROR: response to our PF_KEY %s message for %s %s was of wrong type (%s)"
			, sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type)
			, description, text_said
			, sparse_val_show(pfkey_type_names, bp->msg.sadb_msg_type));
		    success = FALSE;
		}
		else if (response == NULL && bp->msg.sadb_msg_errno != 0)
		{
		    /* KLIPS is signalling a problem */
		    loglog(RC_LOG_SERIOUS
			, "ERROR: PF_KEY %s response for %s %s included errno %u: %s"
			, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
			, description, text_said
			, (unsigned) bp->msg.sadb_msg_errno
			, strerror(bp->msg.sadb_msg_errno));
		    success = FALSE;
		}
	    }
	}
    }

    /* all paths must exit this way to free resources */
    pfkey_extensions_free(extensions);
    pfkey_msg_free(&pfkey_msg);
    return success;
}
Пример #8
0
int
main(int argc, char **argv)
{
/*	int fd; */
	unsigned char action = 0;
	int c;
	
	int error = 0;
	int argcount = argc;
	int em_db_tn, em_db_nl, em_db_xf, em_db_er, em_db_sp;
	int em_db_rj, em_db_es, em_db_ah, em_db_rx, em_db_ky;
	int em_db_gz, em_db_vb;

	struct sadb_ext *extensions[K_SADB_EXT_MAX + 1];
	struct sadb_msg *pfkey_msg;
	
	em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=0;
	em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=0;
	em_db_gz=em_db_vb=0;


	program_name = argv[0];

	while((c = getopt_long(argc, argv, ""/*"s:c:anhvl:+:d"*/, longopts, 0)) != EOF) {
		switch(c) {
		case 'd':
			pfkey_lib_debug = PF_KEY_DEBUG_PARSE_MAX;
			argcount--;
			break;
		case 's':
			if(action) {
				fprintf(stderr, "%s: Only one of '--set', '--clear', '--all' or '--none' options permitted.\n",
					program_name);
				exit(1);
			}
			action = 's';
			em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=0;
			em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=0;
			em_db_gz=em_db_vb=0;
			if(strcmp(optarg, "all") == 0) {
				em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=-1;
				em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=-1;
				em_db_gz=-1;
				em_db_vb= 0;
			} else if(strcmp(optarg, "tunnel") == 0) {
				em_db_tn = -1L;
			} else if(strcmp(optarg, "tncfg") == 0) {
			        em_db_tn = DB_TN_REVEC;
			} else if(strcmp(optarg, "xmit") == 0
					|| strcmp(optarg, "tunnel-xmit") == 0) {
				em_db_tn = DB_TN_XMIT;
			} else if(strcmp(optarg, "netlink") == 0) {
				em_db_nl = -1L;
			} else if(strcmp(optarg, "xform") == 0) {
				em_db_xf = -1L;
			} else if(strcmp(optarg, "eroute") == 0) {
				em_db_er = -1L;
			} else if(strcmp(optarg, "spi") == 0) {
				em_db_sp = -1L;
			} else if(strcmp(optarg, "radij") == 0) {
				em_db_rj = -1L;
			} else if(strcmp(optarg, "esp") == 0) {
				em_db_es = -1L;
			} else if(strcmp(optarg, "ah") == 0) {
				em_db_ah = -1L;
			} else if(strcmp(optarg, "rcv") == 0) {
				em_db_rx = -1L;
			} else if(strcmp(optarg, "pfkey") == 0) {
				em_db_ky = -1L;
			} else if(strcmp(optarg, "comp") == 0) {
				em_db_gz = -1L;
			} else if(strcmp(optarg, "verbose") == 0) {
				em_db_vb = -1L;
			} else {
				fprintf(stdout, "%s: unknown set argument '%s'\n",
						program_name, optarg);
				usage(program_name);
			}
			em_db_nl |= 1 << (sizeof(em_db_nl) * 8 -1);
			break;
		case 'c':
			if(action) {
				fprintf(stderr, "%s: Only one of '--set', '--clear', '--all' or '--none' options permitted.\n",
					program_name);
				exit(1);
			}
			em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=-1;
			em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=-1;
			em_db_gz=em_db_vb=-1;

			action = 'c';
			if(strcmp(optarg, "all") == 0) {
				em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=0;
				em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=0;
				em_db_gz=em_db_vb=0;
			} else if(strcmp(optarg, "tunnel") == 0) {
				em_db_tn = 0;
			} else if(strcmp(optarg, "tunnel-xmit") == 0
				  || strcmp(optarg, "xmit") == 0) {
				em_db_tn = ~DB_TN_XMIT;
			} else if(strcmp(optarg, "netlink") == 0) {
				em_db_nl = 0;
			} else if(strcmp(optarg, "xform") == 0) {
				em_db_xf = 0;
			} else if(strcmp(optarg, "eroute") == 0) {
				em_db_er = 0;
			} else if(strcmp(optarg, "spi") == 0) {
				em_db_sp = 0;
			} else if(strcmp(optarg, "radij") == 0) {
				em_db_rj = 0;
			} else if(strcmp(optarg, "esp") == 0) {
				em_db_es = 0;
			} else if(strcmp(optarg, "ah") == 0) {
				em_db_ah = 0;
			} else if(strcmp(optarg, "rcv") == 0) {
				em_db_rx = 0;
			} else if(strcmp(optarg, "pfkey") == 0) {
				em_db_ky = 0;
			} else if(strcmp(optarg, "comp") == 0) {
				em_db_gz = 0;
			} else if(strcmp(optarg, "verbose") == 0) {
				em_db_vb = 0;
			} else {
				fprintf(stdout, "%s: unknown clear argument '%s'\n",
						program_name, optarg);
				usage(program_name);
			}
			em_db_nl &= ~(1 << (sizeof(em_db_nl) * 8 -1));
			break;
		case 'a':
			if(action) {
				fprintf(stderr, "%s: Only one of '--set', '--clear', '--all' or '--none' options permitted.\n",
					program_name);
				exit(1);
			}
			action = 'a';
			em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=-1;
			em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=-1;
			em_db_gz=-1;
			em_db_vb= 0;
			break;
		case 'n':
			if(action) {
				fprintf(stderr, "%s: Only one of '--set', '--clear', '--all' or '--none' options permitted.\n",
					program_name);
				exit(1);
			}
			action = 'n';
			em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=0;
			em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=0;
			em_db_gz=em_db_vb=0;
			break;
		case 'h':
		case '?':
			usage(program_name);
			exit(1);
		case 'v':
			fprintf(stdout, "klipsdebug (Openswan %s) \n",
				ipsec_version_code());
			fputs(copyright, stdout);
			exit(0);
		case 'l':
			program_name = malloc(strlen(argv[0])
					      + 10 /* update this when changing the sprintf() */
					      + strlen(optarg));
			sprintf(program_name, "%s --label %s",
				argv[0],
				optarg);
			argcount -= 2;
			break;
		case '+': /* optionsfrom */
			optionsfrom(optarg, &argc, &argv, optind, stderr);
			/* no return on error */
			break;
		default:
			fprintf(stdout, "%s: unknown option '%s'\n",
					program_name, argv[optind]);
			break;
		}
	}

	if(argcount == 1) {
		int ret = system("cat /proc/net/ipsec_klipsdebug");
		exit(ret != -1 && WIFEXITED(ret) ? WEXITSTATUS(ret) : 1);
	}

	if(!action) {
		usage(program_name);
	}

	if((pfkey_sock = safe_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);
	}

	pfkey_extensions_init(extensions);

	if((error = pfkey_msg_hdr_build(&extensions[0],
					SADB_X_DEBUG,
					0,
					0,
					++pfkey_seq,
					getpid()))) {
		fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
			program_name, error);
		pfkey_extensions_free(extensions);
		exit(1);
	}
	
	if((error = pfkey_x_debug_build(&extensions[SADB_X_EXT_DEBUG],
					em_db_tn,
					em_db_nl,
					em_db_xf,
					em_db_er,
					em_db_sp,
					em_db_rj,
					em_db_es,
					em_db_ah,
					em_db_rx,
					em_db_ky,
					em_db_gz,
					em_db_vb))) {
		fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
			program_name, 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)) !=
	   (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) {
		fprintf(stderr,
			"%s: pfkey write failed, tried to write %u octets, returning %d with errno=%d.\n",
			program_name,
			(unsigned)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN),
			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;
		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);
		}
		exit(1);
	}

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

	(void) close(pfkey_sock);  /* close the socket */
	exit(0);
}
Пример #9
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);
}
Пример #10
0
int createdelete_virtual(int createdelete, char *virtname)
{
	int vifnum;
	struct sadb_ext *extensions[K_SADB_EXT_MAX + 1];
	struct sadb_msg *pfkey_msg;
	int error;
	int io_error, pfkey_sock;
	
	if(sscanf(virtname, "mast%d", &vifnum)==1) {
		/* good */
	} else if(sscanf(virtname, "ipsec%d", &vifnum)==1) {
		vifnum += IPSECDEV_OFFSET;
	} else {
		return 5;
	}

	pfkey_extensions_init(extensions);

	if((error = pfkey_msg_hdr_build(&extensions[0],
					createdelete,
					0, 0,
					++pfkey_seq,
					getpid()))) {
		fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
			progname, error);
		pfkey_extensions_free(extensions);
		exit(1);
	}

	if((error = pfkey_outif_build(&extensions[SADB_X_EXT_PLUMBIF], vifnum))) {
		fprintf(stderr, "%s: Trouble building outif extension, error=%d.\n",
			progname, 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);
	}

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

	io_error = write(pfkey_sock,
			 pfkey_msg,
			 pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);

	
	if(io_error != (pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) {
		perror("pfkey write");
		exit(2);
	}
	
	return 0;
}
Пример #11
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);
}
Пример #12
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);
}
int sadb_msg_getspi_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply) 
{
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
	int error = 0, found_avail = 0;
	__u32 newspi = 0;
	__u32 spi_max = 0, spi_min = 0;
	struct ipsec_sa sadb_entry;
	struct sadb_address *src, *dst;

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");

		error = -EINVAL;
		goto err;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));
	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
	error = sadb_msg_detect_ext(msg, ext_msgs);

	if (error) {
		PFKEY_DEBUG("error in sadb_msg_detect_ext\n");
		goto err;
	}

	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));

	if (ext_msgs[SADB_EXT_ADDRESS_SRC] &&
	    ext_msgs[SADB_EXT_ADDRESS_DST] &&
	    ext_msgs[SADB_EXT_SPIRANGE])
	{
		src = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_SRC];
		dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];

		memset(&sadb_entry, 0, sizeof(struct ipsec_sa));
		error = sadb_address_to_sockaddr(src, (struct sockaddr*)&sadb_entry.src);
		if (error) {
			PFKEY_DEBUG("error in translate src address\n");
			goto err;
		}
		sadb_entry.prefixlen_s = src->sadb_address_prefixlen;

		error = sadb_address_to_sockaddr(dst, (struct sockaddr*)&sadb_entry.dst);
		if (error) {
			PFKEY_DEBUG("error in translate dst address\n");
		}
		sadb_entry.prefixlen_d = dst->sadb_address_prefixlen;

		spi_min = ((struct sadb_spirange*)ext_msgs[SADB_EXT_SPIRANGE])->sadb_spirange_min;
		spi_max = ((struct sadb_spirange*)ext_msgs[SADB_EXT_SPIRANGE])->sadb_spirange_max;

		/* SPI which is under 255 is reserved by IANA. 
		 * Additionally, 256 and 257 reserved ofr internal use.  */
		if (spi_min < 258) {
			PFKEY_DEBUG("SPI value is reserved.(SPI<258)\n");
			goto err;
		}

		if (spi_min == spi_max) {
			PFKEY_DEBUG("spi_min and spi_max are equal\n");

			error = sadb_find_by_address_proto_spi((struct sockaddr*)&sadb_entry.src, sadb_entry.prefixlen_s, 
								(struct sockaddr*)&sadb_entry.dst, sadb_entry.prefixlen_d, 
								spi_min, msg->sadb_msg_type, NULL /*only check*/);
				
			if (error == -ESRCH) {
				newspi = spi_min;
				found_avail = 1;
			} else {
				PFKEY_DEBUG("sadb_find_by_address_proto_spi return %d\n", error);
				goto err;
			}

		} else if (ntohl(spi_min) < ntohl(spi_max)) {
			/* This codes are derived from FreeS/WAN */
			int i = 0;
                	__u32 rand_val;
			__u32 spi_diff;

			PFKEY_DEBUG("spi_min and spi_max are defference\n");

			while ( ( i < (spi_diff = (ntohl(spi_max) - ntohl(spi_min)))) && !found_avail ) {
				get_random_bytes((void*) &rand_val,
				/* sizeof(extr->tdb->tdb_said.spi) */
                                         ( (spi_diff < (2^8))  ? 1 :
                                           ( (spi_diff < (2^16)) ? 2 :
                                             ( (spi_diff < (2^24)) ? 3 :
                                           4 ) ) ) );
				newspi = htonl(ntohl(spi_min) +
					(rand_val % (spi_diff + 1)));
				PFKEY_DEBUG("new spi is %d\n", ntohl(newspi));

				i++;
				error = sadb_find_by_address_proto_spi( (struct sockaddr*)&sadb_entry.src, sadb_entry.prefixlen_s, 
									(struct sockaddr*)&sadb_entry.dst, sadb_entry.prefixlen_d, 
									newspi, msg->sadb_msg_type, NULL /* only check */);
				if (error == -ESRCH) {
					found_avail = 1;
					break;
				} else {
					PFKEY_DEBUG("sadb_find_by_address_proto_spi return %d\n", error);
					goto err;
				}
			}

		} else {
			PFKEY_DEBUG("invalid spi range\n");
			error = -EINVAL;
			goto err;
		}

		if (found_avail) {
			sadb_entry.spi = newspi;
			sadb_entry.state = SADB_SASTATE_LARVAL;
			error = sadb_append(&sadb_entry);
			if (error) {
				PFKEY_DEBUG("sadb_append return %d\n", error);
				goto err;
			}
		} else {
			PFKEY_DEBUG("could not find available spi\n");
			goto err;
		}

	} else {
		PFKEY_DEBUG("necessary ext messages are not available\n");
		error = -EINVAL;
		goto err;
	}

	error = pfkey_sa_build(&reply_ext_msgs[SADB_EXT_SA], SADB_EXT_SA,
			newspi, 0, 0, 0, 0, SADB_SAFLAGS_PFS);
	if (error) {
		PFKEY_DEBUG("pfkey_address_build faild\n");
		goto err;
	}

	reply_ext_msgs[0] = (struct sadb_ext*) msg;
	reply_ext_msgs[SADB_EXT_ADDRESS_SRC] = ext_msgs[SADB_EXT_ADDRESS_SRC];
	reply_ext_msgs[SADB_EXT_ADDRESS_DST] = ext_msgs[SADB_EXT_ADDRESS_DST];
	error = pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
err:
	return error;
}