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); }
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; }
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; }
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; }
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; }
/* 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; }
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); }
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); }
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; }
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); }
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; }