/* Processs a SADB_ACQUIRE message from KLIPS. * Try to build an opportunistic connection! * See RFC 2367 "PF_KEY Key Management API, Version 2" 3.1.6 * <base, address(SD), (address(P)), (identity(SD),) (sensitivity,) proposal> * - extensions for source and data IP addresses * - optional extensions for identity [not useful for us?] * - optional extension for sensitivity [not useful for us?] * - expension for proposal [not useful for us?] * * ??? We must use the sequence number in creating an SA. * We actually need to create up to 4 SAs each way. Which one? * I guess it depends on the protocol present in the sadb_msg_satype. * For now, we'll ignore this requirement. * * ??? We need some mechanism to make sure that multiple ACQUIRE messages * don't cause a whole bunch of redundant negotiations. */ static void process_pfkey_acquire(pfkey_buf *buf, struct sadb_ext *extensions[SADB_EXT_MAX + 1]) { struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC]; struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST]; int src_proto = srcx->sadb_address_proto; int dst_proto = dstx->sadb_address_proto; ip_address *src = (ip_address*)&srcx[1]; ip_address *dst = (ip_address*)&dstx[1]; ip_subnet ours, his; err_t ugh = NULL; /* assumption: we're only catching our own outgoing packets * so source is our end and destination is the other end. * Verifying this is not actually convenient. * * This stylized control structure yields a complaint or * desired results. For compactness, a pointer value is * treated as a boolean. Logically, the structure is: * keep going as long as things are OK. */ if (buf->msg.sadb_msg_pid == 0 /* we only wish to hear from kernel */ && !(ugh = src_proto == dst_proto? NULL : "src and dst protocols differ") && !(ugh = addrtypeof(src) == addrtypeof(dst)? NULL : "conflicting address types") && !(ugh = addrtosubnet(src, &ours)) && !(ugh = addrtosubnet(dst, &his))) record_and_initiate_opportunistic(&ours, &his, 0, "%acquire-pfkey"); if (ugh != NULL) plog("SADB_ACQUIRE message from KLIPS malformed: %s", ugh); }
static void natd_hash(const struct hash_desc *hasher, unsigned char *hash, const u_int8_t *icookie, const u_int8_t *rcookie, const ip_address *ip, u_int16_t port /* host order */) { union hash_ctx ctx; if (is_zero_cookie(icookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, icookie is zero !!")); if (is_zero_cookie(rcookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, rcookie is zero !!")); /* * RFC 3947 * * HASH = HASH(CKY-I | CKY-R | IP | Port) * * All values in network order */ hasher->hash_init(&ctx); hasher->hash_update(&ctx, icookie, COOKIE_SIZE); hasher->hash_update(&ctx, rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; case AF_INET6: hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr, sizeof(ip->u.v6.sin6_addr.s6_addr)); break; } { u_int16_t netorder_port = htons(port); hasher->hash_update(&ctx, (const u_char *)&netorder_port, sizeof(netorder_port)); } hasher->hash_final(hash, &ctx); DBG(DBG_NATT, { DBG_log("natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len); DBG_dump("natd_hash: icookie=", icookie, COOKIE_SIZE); DBG_dump("natd_hash: rcookie=", rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: DBG_dump("natd_hash: ip=", &ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; } DBG_log("natd_hash: port=%d", port); DBG_dump("natd_hash: hash=", hash, hasher->hash_digest_len); });
static void natd_hash(const struct hash_desc *hasher, unsigned char *hash, const u_int8_t *icookie, const u_int8_t *rcookie, const ip_address *ip, u_int16_t port /* host order */) { if (is_zero_cookie(icookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, icookie is zero !!")); if (is_zero_cookie(rcookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, rcookie is zero !!")); /* * RFC 3947 * * HASH = HASH(CKY-I | CKY-R | IP | Port) * * All values in network order */ struct crypt_hash *ctx = crypt_hash_init(hasher, "NATD", DBG_CRYPT); crypt_hash_digest_bytes(ctx, "ICOOKIE", icookie, COOKIE_SIZE); crypt_hash_digest_bytes(ctx, "RCOOKIE", rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: crypt_hash_digest_bytes(ctx, "SIN_ADDR", (const u_char *)&ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; case AF_INET6: crypt_hash_digest_bytes(ctx, "SIN6_ADDR", (const u_char *)&ip->u.v6.sin6_addr.s6_addr, sizeof(ip->u.v6.sin6_addr.s6_addr)); break; } { u_int16_t netorder_port = htons(port); crypt_hash_digest_bytes(ctx, "PORT", &netorder_port, sizeof(netorder_port)); } crypt_hash_final_bytes(&ctx, hash, hasher->hash_digest_len); DBG(DBG_NATT, { DBG_log("natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len); DBG_dump("natd_hash: icookie=", icookie, COOKIE_SIZE); DBG_dump("natd_hash: rcookie=", rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: DBG_dump("natd_hash: ip=", &ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; } DBG_log("natd_hash: port=%d", port); DBG_dump("natd_hash: hash=", hash, hasher->hash_digest_len); });
int ikev2_calc_iprangediff(ip_address low, ip_address high) { unsigned const char *hp; unsigned const char *lp, *t; unsigned char *dp; ip_address diff; size_t n; size_t n2; int i; int carry = 0; /* initialize all the contents to sensible values */ diff = low; if (addrtypeof(&high) != addrtypeof(&low)) return -1; n = addrbytesptr(&high, &hp); if (n == 0) return -1; n2 = addrbytesptr(&low, &lp); if (n != n2) return -1; addrbytesptr_write(&diff, &dp); for(i=0; i<n; i++) { if(hp[i]==lp[i]) { dp[i]=0; continue; } break; } /* two values are the same -- no diff */ if(i==n) return 0; if(hp[i] < lp[i]) { /* need to swap! */ t=hp; hp=lp; lp=t; } for(i=n-1; i>=0; i--) { int val=hp[i]-lp[i]-carry; if(val < 0) { val += 256; carry=1; } else { carry=0; } dp[i]=val; } return ikev2_highorder_zerobits(diff); }
static void _natd_hash(const struct hash_desc *hasher, unsigned char *hash , u_int8_t *icookie, u_int8_t *rcookie , const ip_address *ip, u_int16_t port) { union hash_ctx ctx; if (is_zero_cookie(icookie)) DBG_log("_natd_hash: Warning, icookie is zero !!"); if (is_zero_cookie(rcookie)) DBG_log("_natd_hash: Warning, rcookie is zero !!"); /** * draft-ietf-ipsec-nat-t-ike-01.txt * * HASH = HASH(CKY-I | CKY-R | IP | Port) * * All values in network order */ hasher->hash_init(&ctx); hasher->hash_update(&ctx, icookie, COOKIE_SIZE); hasher->hash_update(&ctx, rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; case AF_INET6: hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr, sizeof(ip->u.v6.sin6_addr.s6_addr)); break; } hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t)); hasher->hash_final(hash, &ctx); #ifdef NAT_D_DEBUG DBG(DBG_NATT, DBG_log("_natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len); DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE); DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: DBG_dump("_natd_hash: ip=", &ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; } DBG_log("_natd_hash: port=%d", ntohs(port)); DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len); );
bool emit_redirect_notification_decoded_dest( v2_notification_t ntype, const ip_address *dest_ip, const char *dest_str, const chunk_t *nonce, /* optional */ pb_stream *pbs) { struct ikev2_redirect_part gwi; size_t id_len; const unsigned char *id_bytes; if (dest_ip == NULL) { id_len = strlen(dest_str); id_bytes = (const unsigned char *)dest_str; } else { passert(dest_str == NULL); switch (addrtypeof(dest_ip)) { case AF_INET: gwi.gw_identity_type = GW_IPV4; break; case AF_INET6: gwi.gw_identity_type = GW_IPV6; break; default: bad_case(addrtypeof(dest_ip)); } id_len = addrbytesptr_read(dest_ip, &id_bytes); } if (id_len > 0xFF) { /* ??? what should we do? */ loglog(RC_LOG_SERIOUS, "redirect destination longer than 255 octets; ignoring"); return false; } gwi.gw_identity_len = id_len; passert(nonce == NULL || (nonce->len >= IKEv2_MINIMUM_NONCE_SIZE && nonce->len <= IKEv2_MAXIMUM_NONCE_SIZE)); pb_stream gwid_pbs; return - emit_v2Npl(ntype, pbs, &gwid_pbs) && out_struct(&gwi, &ikev2_redirect_desc, &gwid_pbs, NULL) && out_raw(id_bytes, id_len , &gwid_pbs, "redirect ID") && (nonce == NULL || out_chunk(*nonce, &gwid_pbs, "redirect ID len")) && (close_output_pbs(&gwid_pbs), true); }
void iptoid(const ip_address *ip, struct id *id) { *id = empty_id; switch (addrtypeof(ip)) { case AF_INET: id->kind = ID_IPV4_ADDR; break; case AF_INET6: id->kind = ID_IPV6_ADDR; break; default: bad_case(addrtypeof(ip)); } id->ip_addr = *ip; }
/* build an ID payload * Note: no memory is allocated for the body of the payload (tl->ptr). * We assume it will end up being a pointer into a sufficiently * stable datastructure. It only needs to last a short time. */ void build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end) { const struct id *id = resolve_myid(&end->id); zero(hd); zero(tl); hd->isaiid_idtype = id->kind; switch (id->kind) { case ID_NONE: hd->isaiid_idtype = aftoinfo(addrtypeof(&end->host_addr))->id_addr; tl->len = addrbytesptr(&end->host_addr, &tl->ptr); /* sets tl->ptr too */ break; case ID_FQDN: case ID_USER_FQDN: case ID_DER_ASN1_DN: case ID_KEY_ID: *tl = id->name; break; case ID_IPV4_ADDR: case ID_IPV6_ADDR: tl->len = addrbytesptr(&id->ip_addr, &tl->ptr); /* sets tl->ptr too */ break; case ID_NULL: tl->len = 0; tl->ptr = NULL; break; default: bad_case(id->kind); } }
/* ipcmp compares the two ip_address values a and b. * It returns -1, 0, or +1 if a is, respectively, * less than, equal to, or greater than b. */ static int ipcmp(ip_address *a, ip_address *b) { if (addrtypeof(a) != addrtypeof(b)) { return addrtypeof(a) < addrtypeof(b) ? -1 : 1; } else if (sameaddr(a, b)) { return 0; } else { const struct sockaddr *sa = sockaddrof(a), *sb = sockaddrof(b); passert(addrtypeof(a) == AF_INET); /* not yet implemented IPv6 version :-( */ return (ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr) < ntohl(((const struct sockaddr_in *)sb)->sin_addr.s_addr)) ? -1 : 1; } }
/***************************************************************** *函数名称:addrtot *功能 :2 进制地址转换成字符型 * addrtot - convert binary address to text * (dotted decimal or IPv6 string) * ******************************************************************* * * * ******************************************************************/ size_t addrtot(const ip_address *src, int format, char *dst, size_t dstlen) { const unsigned char *b; size_t n; char buf[1+ADDRTOT_BUF+1]; /* :address: */ char *p; int t = addrtypeof(src); #define TF(t, f) (((t)<<8) | (f)) n = addrbytesptr(src, &b); if (n == 0) { bad: dst[0]='\0'; strncat(dst, "invalid", dstlen); return sizeof("invalid"); } switch (TF(t, format)) { case TF(AF_INET, 0): n = normal4(b, n, buf, &p); break; case TF(AF_INET6, 0): n = normal6(b, n, buf, &p, 1); break; case TF(AF_INET, 'Q'): n = normal4(b, n, buf, &p); break; case TF(AF_INET6, 'Q'): n = normal6(b, n, buf, &p, 0); break; case TF(AF_INET, 'r'): n = reverse4(b, n, buf, &p); break; case TF(AF_INET6, 'r'): n = reverse6(b, n, buf, &p); break; default: /* including (AF_INET, 'R') */ goto bad; break; } if (dstlen > 0) { if (dstlen < n) p[dstlen - 1] = '\0'; strcpy(dst, p); } return n; }
/* * returns true if the subnet looks valid. */ bool isvalidsubnet(const ip_subnet *sub) { int t = addrtypeof(&sub->addr); switch (t) { case AF_INET: if (sub->maskbits <= 0 && sub->maskbits > 32) return FALSE; break; case AF_INET6: if (sub->maskbits <= 0 && sub->maskbits > 128) return FALSE; break; default: return FALSE; } return TRUE; }
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); }
bool cert_VerifySubjectAltName(const CERTCertificate *cert, const char *name) { SECStatus rv; SECItem subAltName; PLArenaPool *arena = NULL; CERTGeneralName *nameList = NULL; CERTGeneralName *current = NULL; bool san_ip = FALSE; unsigned int len = strlen(name); ip_address myip; rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, &subAltName); if (rv != SECSuccess) { DBG(DBG_X509, DBG_log("certificate contains no subjectAltName extension")); return FALSE; } if (tnatoaddr(name, 0, AF_UNSPEC, &myip) == NULL) san_ip = TRUE; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); passert(arena != NULL); nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName); passert(current != NULL); do { switch (current->type) { case certDNSName: case certRFC822Name: if (san_ip) break; if (current->name.other.len == len) { if (memcmp(current->name.other.data, name, len) == 0) { DBG(DBG_X509, DBG_log("subjectAltname %s found in certificate", name)); PORT_FreeArena(arena, PR_FALSE); return TRUE; } } if (current->name.other.len != 0 && current->name.other.len < IDTOA_BUF) { char osan[IDTOA_BUF]; memcpy(osan,current->name.other.data, current->name.other.len); osan[current->name.other.len] = '\0'; DBG(DBG_X509, DBG_log("subjectAltname (len=%d) %s not match %s", current->name.other.len, osan, name)); } else { DBG(DBG_X509, DBG_log("subjectAltname <TOO BIG TO PRINT> does not match %s", name)); } break; case certIPAddress: if (!san_ip) break; if ((current->name.other.len == 4) && (addrtypeof(&myip) == AF_INET)) { if (memcmp(current->name.other.data, &myip.u.v4.sin_addr.s_addr, 4) == 0) { DBG(DBG_X509, DBG_log("subjectAltname IPv4 matches %s", name)); PORT_FreeArena(arena, PR_FALSE); return TRUE; } else { DBG(DBG_X509, DBG_log("subjectAltname IPv4 does not match %s", name)); break; } } if ((current->name.other.len == 16) && (addrtypeof(&myip) == AF_INET6)) { if (memcmp(current->name.other.data, &myip.u.v6.sin6_addr.s6_addr, 16) == 0) { DBG(DBG_X509, DBG_log("subjectAltname IPv6 matches %s", name)); PORT_FreeArena(arena, PR_FALSE); return TRUE; } else { DBG(DBG_X509, DBG_log("subjectAltname IPv6 does not match %s", name)); break; } } DBG(DBG_X509, DBG_log("subjectAltnamea IP address family mismatch for %s", name)); break; default: break; } current = CERT_GetNextGeneralName(current); } while (current != nameList); loglog(RC_LOG_SERIOUS, "No matching subjectAltName found"); /* Don't free nameList, it's part of the arena. */ PORT_FreeArena(arena, PR_FALSE); return FALSE; }
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); }
static bool validate_end(struct ub_ctx *dnsctx , #endif struct starter_conn *conn_st, struct starter_end *end, const char *leftright, bool resolvip UNUSED, err_t *perr) { err_t er = NULL; char *err_str = NULL; int family = conn_st->options[KBF_CONNADDRFAMILY]; bool err = FALSE; # define ERR_FOUND(...) { err |= error_append(&err_str, __VA_ARGS__); } if (!end->options_set[KNCF_IP]) conn_st->state = STATE_INCOMPLETE; end->addrtype = end->options[KNCF_IP]; end->addr_family = family; /* validate the KSCF_IP/KNCF_IP */ switch (end->addrtype) { case KH_ANY: anyaddr(family, &(end->addr)); break; case KH_IFACE: /* generally, this doesn't show up at this stage */ starter_log(LOG_LEVEL_DEBUG, "starter: %s is KH_IFACE", leftright); break; case KH_IPADDR: assert(end->strings[KSCF_IP] != NULL); if (end->strings[KSCF_IP][0] == '%') { pfree(end->iface); end->iface = clone_str(end->strings[KSCF_IP] + 1, "KH_IPADDR end->iface"); if (!starter_iface_find(end->iface, family, &end->addr, &end->nexthop)) conn_st->state = STATE_INVALID; /* not numeric, so set the type to the iface type */ end->addrtype = KH_IFACE; break; } er = ttoaddr_num(end->strings[KNCF_IP], 0, family, &(end->addr)); if (er != NULL) { /* not numeric, so set the type to the string type */ end->addrtype = KH_IPHOSTNAME; } if (end->id == NULL) { ipstr_buf b; end->id = clone_str(ipstr(&end->addr, &b), "end if"); } break; case KH_OPPO: conn_st->policy |= POLICY_OPPORTUNISTIC; break; case KH_OPPOGROUP: conn_st->policy |= POLICY_OPPORTUNISTIC | POLICY_GROUP; break; case KH_GROUP: conn_st->policy |= POLICY_GROUP; break; case KH_IPHOSTNAME: /* generally, this doesn't show up at this stage */ starter_log(LOG_LEVEL_DEBUG, "starter: %s is KH_IPHOSTNAME", leftright); break; case KH_DEFAULTROUTE: starter_log(LOG_LEVEL_DEBUG, "starter: %s is KH_DEFAULTROUTE", leftright); break; case KH_NOTSET: starter_log(LOG_LEVEL_DEBUG, "starter: %s is KH_NOTSET", leftright); break; } /* validate the KSCF_SUBNET */ if (end->strings_set[KSCF_SUBNET]) { char *value = end->strings[KSCF_SUBNET]; if (end->strings_set[KSCF_ADDRESSPOOL]) { ERR_FOUND("cannot specify both %ssubnet= and %saddresspool=", leftright, leftright); } if (startswith(value, "vhost:") || startswith(value, "vnet:")) { er = NULL; end->virt = clone_str(value, "validate_end item"); } else { end->has_client = TRUE; er = ttosubnet(value, 0, family, &(end->subnet)); } if (er != NULL) ERR_FOUND("bad subnet %ssubnet=%s [%s]", leftright, value, er); } /* set nexthop address to something consistent, by default */ anyaddr(family, &end->nexthop); anyaddr(addrtypeof(&end->addr), &end->nexthop); /* validate the KSCF_NEXTHOP */ if (end->strings_set[KSCF_NEXTHOP]) { char *value = end->strings[KSCF_NEXTHOP]; if (strcaseeq(value, "%defaultroute")) { end->nexttype = KH_DEFAULTROUTE; } else { if (tnatoaddr(value, strlen(value), AF_INET, &(end->nexthop)) != NULL && tnatoaddr(value, strlen(value), AF_INET6, &(end->nexthop)) != NULL) { #ifdef DNSSEC starter_log(LOG_LEVEL_DEBUG, "Calling unbound_resolve() for %snexthop value", leftright); if (!unbound_resolve(dnsctx, value, strlen(value), AF_INET, &(end->nexthop)) && !unbound_resolve(dnsctx, value, strlen(value), AF_INET6, &(end->nexthop))) ERR_FOUND("bad value for %snexthop=%s\n", leftright, value); #else er = ttoaddr(value, 0, family, &(end->nexthop)); if (er != NULL) ERR_FOUND("bad value for %snexthop=%s [%s]", leftright, value, er); #endif } end->nexttype = KH_IPADDR; } } else { #if 0 if (conn_st->policy & POLICY_OPPORTUNISTIC) end->nexttype = KH_DEFAULTROUTE; #endif anyaddr(family, &end->nexthop); if (end->addrtype == KH_DEFAULTROUTE) { end->nexttype = KH_DEFAULTROUTE; } } /* validate the KSCF_ID */ if (end->strings_set[KSCF_ID]) { char *value = end->strings[KSCF_ID]; pfreeany(end->id); end->id = clone_str(value, "end->id"); } if (end->options_set[KSCF_RSAKEY1]) { end->rsakey1_type = end->options[KSCF_RSAKEY1]; end->rsakey2_type = end->options[KSCF_RSAKEY2]; switch (end->options[KSCF_RSAKEY1]) { case PUBKEY_DNS: case PUBKEY_DNSONDEMAND: end->key_from_DNS_on_demand = TRUE; break; default: end->key_from_DNS_on_demand = FALSE; /* validate the KSCF_RSAKEY1/RSAKEY2 */ if (end->strings[KSCF_RSAKEY1] != NULL) { char *value = end->strings[KSCF_RSAKEY1]; pfreeany(end->rsakey1); end->rsakey1 = (unsigned char *)clone_str(value,"end->rsakey1"); } if (end->strings[KSCF_RSAKEY2] != NULL) { char *value = end->strings[KSCF_RSAKEY2]; pfreeany(end->rsakey2); end->rsakey2 = (unsigned char *)clone_str(value,"end->rsakey2"); } } } /* validate the KSCF_SOURCEIP, if any, and if set, * set the subnet to same value, if not set. */ if (end->strings_set[KSCF_SOURCEIP]) { char *value = end->strings[KSCF_SOURCEIP]; if (tnatoaddr(value, strlen(value), AF_INET, &(end->sourceip)) != NULL && tnatoaddr(value, strlen(value), AF_INET6, &(end->sourceip)) != NULL) { #ifdef DNSSEC starter_log(LOG_LEVEL_DEBUG, "Calling unbound_resolve() for %ssourceip value", leftright); if (!unbound_resolve(dnsctx, value, strlen(value), AF_INET, &(end->sourceip)) && !unbound_resolve(dnsctx, value, strlen(value), AF_INET6, &(end->sourceip))) ERR_FOUND("bad value for %ssourceip=%s\n", leftright, value); #else er = ttoaddr(value, 0, family, &(end->sourceip)); if (er != NULL) ERR_FOUND("bad addr %ssourceip=%s [%s]", leftright, value, er); #endif } else { er = tnatoaddr(value, 0, family, &(end->sourceip)); if (er != NULL) ERR_FOUND("bad numerical addr %ssourceip=%s [%s]", leftright, value, er); } if (!end->has_client) { starter_log(LOG_LEVEL_INFO, "%ssourceip= used but not %ssubnet= defined, defaulting %ssubnet to %s", leftright, leftright, leftright, value); er = addrtosubnet(&end->sourceip, &end->subnet); if (er != NULL) { ERR_FOUND("attempt to default %ssubnet from %s failed: %s", leftright, value, er); } end->has_client = TRUE; end->has_client_wildcard = FALSE; } } /* copy certificate path name */ if (end->strings_set[KSCF_CERT]) end->cert = clone_str(end->strings[KSCF_CERT], "KSCF_CERT"); if (end->strings_set[KSCF_CA]) end->ca = clone_str(end->strings[KSCF_CA], "KSCF_CA"); if (end->strings_set[KSCF_UPDOWN]) end->updown = clone_str(end->strings[KSCF_UPDOWN], "KSCF_UPDOWN"); if (end->strings_set[KSCF_PROTOPORT]) { err_t ugh; char *value = end->strings[KSCF_PROTOPORT]; ugh = ttoprotoport(value, 0, &end->protocol, &end->port, &end->has_port_wildcard); if (ugh != NULL) ERR_FOUND("bad %sprotoport=%s [%s]", leftright, value, ugh); } if (end->strings_set[KSCF_ADDRESSPOOL]) { char *addresspool = end->strings[KSCF_ADDRESSPOOL]; if (end->strings_set[KSCF_SUBNET]) ERR_FOUND("cannot specify both %ssubnet= and %saddresspool=", leftright, leftright); starter_log(LOG_LEVEL_DEBUG, "connection's %saddresspool set to: %s", leftright, end->strings[KSCF_ADDRESSPOOL] ); er = ttorange(addresspool, 0, AF_INET, &end->pool_range, TRUE); if (er != NULL) ERR_FOUND("bad %saddresspool=%s [%s]", leftright, addresspool, er); } if (end->options_set[KNCF_XAUTHSERVER] || end->options_set[KNCF_XAUTHCLIENT]) conn_st->policy |= POLICY_XAUTH; /* KSCF_SUBNETWITHIN --- not sure what to do with it. KSCF_ESPENCKEY --- todo (manual keying) KSCF_ESPAUTHKEY --- todo (manual keying) KSCF_SOURCEIP = 16, KSCF_MAX = 19 */ if (err) *perr = err_str; return err; # undef ERR_FOUND }
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); }
/** * Validate that yes in fact we are one side of the tunnel * * The function checks that IP addresses are valid, nexthops are * present (if needed) as well as policies, and sets the leftID * from the left= if it isn't set. * * @param conn_st a connection definition * @param end a connection end * @param left boolean (are we 'left'? 1 = yes, 0 = no) * @param perr pointer to char containing error value * @return bool TRUE if failed */ static bool validate_end(struct starter_conn *conn_st , struct starter_end *end , bool left , bool resolvip UNUSED , err_t *perr) { err_t er = NULL; char *err_str = NULL; const char *leftright=(left ? "left" : "right"); int family = conn_st->options[KBF_CONNADDRFAMILY]; bool err = FALSE; #define ERR_FOUND(args...) do { err += error_append(&err_str, ##args); } while(0) if(!end->options_set[KNCF_IP]) { conn_st->state = STATE_INCOMPLETE; } end->addrtype=end->options[KNCF_IP]; end->addr_family = family; /* validate the KSCF_IP/KNCF_IP */ switch(end->addrtype) { case KH_ANY: anyaddr(family, &(end->addr)); break; case KH_IFACE: /* generally, this doesn't show up at this stage */ break; case KH_IPADDR: /* right=/left= */ assert(end->strings[KSCF_IP] != NULL); if (end->strings[KSCF_IP][0]=='%') { if (end->iface) pfree(end->iface); end->iface = clone_str(end->strings[KSCF_IP] + 1, "KH_IPADDR end->iface"); if (starter_iface_find(end->iface, family, &(end->addr), &(end->nexthop)) == -1) { conn_st->state = STATE_INVALID; } /* not numeric, so set the type to the iface type */ end->addrtype = KH_IFACE; break; } er = ttoaddr_num(end->strings[KNCF_IP], 0, family, &(end->addr)); if(er) { /* not numeric, so set the type to the string type */ end->addrtype = KH_IPHOSTNAME; } if(end->id == NULL) { char idbuf[ADDRTOT_BUF]; addrtot(&end->addr, 0, idbuf, sizeof(idbuf)); end->id= clone_str(idbuf, "end id"); } break; case KH_OPPO: conn_st->policy |= POLICY_OPPO; break; case KH_OPPOGROUP: conn_st->policy |= POLICY_OPPO|POLICY_GROUP; break; case KH_GROUP: conn_st->policy |= POLICY_GROUP; break; case KH_IPHOSTNAME: /* XXX */ break; case KH_DEFAULTROUTE: break; case KH_NOTSET: break; } /* validate the KSCF_SUBNET */ if(end->strings_set[KSCF_SUBNET]) { char *value = end->strings[KSCF_SUBNET]; if ( ((strlen(value)>=6) && (strncmp(value,"vhost:",6)==0)) || ((strlen(value)>=5) && (strncmp(value,"vnet:",5)==0)) ) { er = NULL; end->virt = clone_str(value, "end->virt"); } else { end->has_client = TRUE; er = ttosubnet(value, 0, 0, &(end->subnet)); } if (er) ERR_FOUND("bad subnet %ssubnet=%s [%s] family=%s", leftright, value, er, family2str(family)); } /* set nexthop address to something consistent, by default */ anyaddr(family, &end->nexthop); anyaddr(addrtypeof(&end->addr), &end->nexthop); /* validate the KSCF_NEXTHOP */ if(end->strings_set[KSCF_NEXTHOP]) { char *value = end->strings[KSCF_NEXTHOP]; if(strcasecmp(value, "%defaultroute")==0) { end->nexttype=KH_DEFAULTROUTE; } else { if (tnatoaddr(value, strlen(value), AF_INET, &(end->nexthop)) != NULL && tnatoaddr(value, strlen(value), AF_INET6, &(end->nexthop)) != NULL) { er = ttoaddr(value, 0, family, &(end->nexthop)); if (er) ERR_FOUND("bad addr %snexthop=%s [%s]", leftright, value, er); } end->nexttype = KH_IPADDR; } } else { if (end->addrtype == KH_DEFAULTROUTE) { end->nexttype = KH_DEFAULTROUTE; } anyaddr(family, &end->nexthop); } /* validate the KSCF_ID */ if(end->strings_set[KSCF_ID]) { char *value = end->strings[KSCF_ID]; pfreeany(end->id); end->id = clone_str(value, "end->id"); } if(end->options_set[KSCF_RSAKEY1]) { end->rsakey1_type = end->options[KSCF_RSAKEY1]; end->rsakey2_type = end->options[KSCF_RSAKEY2]; switch(end->rsakey1_type) { case PUBKEY_DNS: case PUBKEY_DNSONDEMAND: end->key_from_DNS_on_demand = TRUE; break; default: end->key_from_DNS_on_demand = FALSE; /* validate the KSCF_RSAKEY1/RSAKEY2 */ if(end->strings[KSCF_RSAKEY1] != NULL) { char *value = end->strings[KSCF_RSAKEY1]; pfreeany(end->rsakey1); end->rsakey1 = (unsigned char *)clone_str(value,"end->rsakey1"); } if(end->strings[KSCF_RSAKEY2] != NULL) { char *value = end->strings[KSCF_RSAKEY2]; pfreeany(end->rsakey2); end->rsakey2 = (unsigned char *)clone_str(value,"end->rsakey2"); } } } /* validate the KSCF_SOURCEIP, if any, and if set, * set the subnet to same value, if not set. */ if(end->strings_set[KSCF_SOURCEIP]) { char *value = end->strings[KSCF_SOURCEIP]; if (tnatoaddr(value, strlen(value), AF_INET, &(end->sourceip)) != NULL && tnatoaddr(value, strlen(value), AF_INET6, &(end->sourceip)) != NULL) { er = ttoaddr(value, 0, 0, &(end->sourceip)); if (er) ERR_FOUND("bad addr %ssourceip=%s [%s]", leftright, value, er); } else { er = tnatoaddr(value, 0, 0, &(end->sourceip)); if (er) ERR_FOUND("bad numerical addr %ssourceip=%s [%s]", leftright, value, er); } if(!end->has_client) { starter_log(LOG_LEVEL_INFO, "defaulting %ssubnet to %s\n", leftright, value); er = addrtosubnet(&end->sourceip, &end->subnet); if (er) ERR_FOUND("attempt to default %ssubnet from %s failed: %s", leftright, value, er); end->has_client = TRUE; end->has_client_wildcard = FALSE; } } /* copy certificate path name */ if(end->strings_set[KSCF_CERT]) { end->cert = clone_str(end->strings[KSCF_CERT], "KSCF_CERT"); } if(end->strings_set[KSCF_CA]) { end->ca = clone_str(end->strings[KSCF_CA], "KSCF_CA"); } if(end->strings_set[KSCF_UPDOWN]) { end->updown = clone_str(end->strings[KSCF_UPDOWN], "KSCF_UPDOWN"); } if(end->strings_set[KSCF_PROTOPORT]) { err_t ugh; char *value = end->strings[KSCF_PROTOPORT]; ugh = ttoprotoport(value, 0, &end->protocol, &end->port, &end->has_port_wildcard); if (ugh) ERR_FOUND("bad %sprotoport=%s [%s]", leftright, value, ugh); } if (end->options_set[KNCF_XAUTHSERVER] || end->options_set[KNCF_XAUTHCLIENT]) { conn_st->policy |= POLICY_XAUTH; } /* KSCF_SUBNETWITHIN --- not sure what to do with it. KSCF_ESPENCKEY --- todo (manual keying) KSCF_ESPAUTHKEY --- todo (manual keying) KSCF_SOURCEIP = 16, KSCF_MAX = 19 */ if(err) *perr = err_str; return err; # undef ERR_FOUND }
void recv_pcap_packet_gen(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) { struct msg_digest *md; u_int32_t *dlt; struct iphdr *ip; struct udphdr *udp; u_char *ike; const struct iface_port *ifp = &if1; int packet_len; err_t from_ugh; union { struct sockaddr sa; struct sockaddr_in sa_in4; struct sockaddr_in6 sa_in6; } from; md = alloc_md(); dlt = (u_int32_t *)bytes; if (*dlt != PF_INET) return; ip = (struct iphdr *)(dlt + 1); udp = (struct udphdr *)(dlt + ip->ihl + 1); ike = (u_char *)(udp + 1); from.sa_in4.sin_addr.s_addr = ip->saddr; from.sa_in4.sin_port = udp->source; md->iface = ifp; packet_len = h->len - (ike - bytes); happy(anyaddr(addrtypeof(&ifp->ip_addr), &md->sender)); from_ugh = initaddr((void *) &from.sa_in4.sin_addr, sizeof(from.sa_in4.sin_addr), AF_INET, &md->sender); setportof(from.sa_in4.sin_port, &md->sender); md->sender_port = ntohs(from.sa_in4.sin_port); cur_from = &md->sender; cur_from_port = md->sender_port; /* Clone actual message contents * and set up md->packet_pbs to describe it. */ init_pbs(&md->packet_pbs, clone_bytes(ike, packet_len, "message buffer in comm_handle()"), packet_len, "packet"); DBG_log("*received %d bytes from %s:%u on %s (port=%d)", (int) pbs_room(&md->packet_pbs), ip_str(&md->sender), (unsigned) md->sender_port, ifp->ip_dev->id_rname, ifp->port); DBG_dump("", md->packet_pbs.start, pbs_room(&md->packet_pbs)); process_packet(&md); if (md != NULL) release_md(md); cur_state = NULL; reset_cur_connection(); cur_from = NULL; }
static void bsdkame_process_raw_ifaces(struct raw_iface *rifaces) { struct raw_iface *ifp; /* * There are no virtual interfaces, so all interfaces are valid */ for (ifp = rifaces; ifp != NULL; ifp = ifp->next) { bool after = FALSE; /* has vfp passed ifp on the list? */ bool bad = FALSE; struct raw_iface *vfp; for (vfp = rifaces; vfp != NULL; vfp = vfp->next) { if (vfp == ifp) { after = TRUE; } else if (sameaddr(&ifp->addr, &vfp->addr)) { if (after) { loglog(RC_LOG_SERIOUS , "IP interfaces %s and %s share address %s!" , ifp->name, vfp->name, ip_str(&ifp->addr)); } bad = TRUE; } } if (bad) continue; /* We've got all we need; see if this is a new thing: * search old interfaces list. */ { struct iface_port **p = &interfaces; for (;;) { struct iface_port *q = *p; struct iface_dev *id = NULL; /* search is over if at end of list */ if (q == NULL) { /* matches nothing -- create a new entry */ int fd = create_socket(ifp, ifp->name, pluto_port); if (fd < 0) break; #ifdef NAT_TRAVERSAL if (nat_traversal_support_non_ike && addrtypeof(&ifp->addr) == AF_INET) { nat_traversal_espinudp_socket(fd, "IPv4", ESPINUDP_WITH_NON_IKE); } #endif q = alloc_thing(struct iface_port, "struct iface_port"); id = alloc_thing(struct iface_dev, "struct iface_dev"); LIST_INSERT_HEAD(&interface_dev, id, id_entry); q->ip_dev = id; id->id_rname = clone_str(ifp->name, "real device name"); id->id_vname = clone_str(ifp->name, "virtual device name"); id->id_count++; q->ip_addr = ifp->addr; q->fd = fd; q->next = interfaces; q->change = IFN_ADD; q->port = pluto_port; q->ike_float = FALSE; interfaces = q; openswan_log("adding interface %s/%s %s:%d" , q->ip_dev->id_vname , q->ip_dev->id_rname , ip_str(&q->ip_addr) , q->port); #ifdef NAT_TRAVERSAL /* * right now, we do not support NAT-T on IPv6, because * the kernel did not support it, and gave an error * it one tried to turn it on. */ if (nat_traversal_support_port_floating && addrtypeof(&ifp->addr) == AF_INET) { fd = create_socket(ifp, id->id_vname, NAT_T_IKE_FLOAT_PORT); if (fd < 0) break; nat_traversal_espinudp_socket(fd, "IPv4" , ESPINUDP_WITH_NON_ESP); q = alloc_thing(struct iface_port, "struct iface_port"); q->ip_dev = id; id->id_count++; q->ip_addr = ifp->addr; setportof(htons(NAT_T_IKE_FLOAT_PORT), &q->ip_addr); q->port = NAT_T_IKE_FLOAT_PORT; q->fd = fd; q->next = interfaces; q->change = IFN_ADD; q->ike_float = TRUE; interfaces = q; openswan_log("adding interface %s/%s %s:%d" , q->ip_dev->id_vname, q->ip_dev->id_rname , ip_str(&q->ip_addr) , q->port); } #endif break; } /* search over if matching old entry found */ if (streq(q->ip_dev->id_rname, ifp->name) && streq(q->ip_dev->id_vname, ifp->name) && sameaddr(&q->ip_addr, &ifp->addr)) { /* matches -- rejuvinate old entry */ q->change = IFN_KEEP; #ifdef NAT_TRAVERSAL /* look for other interfaces to keep (due to NAT-T) */ for (q = q->next ; q ; q = q->next) { if (streq(q->ip_dev->id_rname, ifp->name) && streq(q->ip_dev->id_vname, ifp->name) && sameaddr(&q->ip_addr, &ifp->addr)) { q->change = IFN_KEEP; } } #endif break; } /* try again */ p = &q->next; } /* for (;;) */ }
/** returns a host pair based upon addresses. * * find_host_pair is given a pair of addresses, plus UDP ports, and * returns a host_pair entry that covers it. It also moves the relevant * pair description to the beginning of the list, so that it can be * found faster next time. */ struct host_pair *find_host_pair(const ip_address *myaddr, u_int16_t myport, const ip_address *hisaddr, u_int16_t hisport) { struct host_pair *p, *prev; /* default hisaddr to an appropriate any */ if (hisaddr == NULL) { #if 0 /* broken */ const struct af_info *af = aftoinfo(addrtypeof(myaddr)); if (af == NULL) af = aftoinfo(AF_INET); if (af) hisaddr = af->any; #else hisaddr = aftoinfo(addrtypeof(myaddr))->any; #endif } /* * look for a host-pair that has the right set of ports/address. * */ /* * for the purposes of comparison, port 500 and 4500 are identical, * but other ports are not. * So if any port==4500, then set it to 500. * But we can also have non-RFC values for pluto_port and pluto_nat_port */ if (myport == pluto_nat_port) myport = pluto_port; if (hisport == pluto_nat_port) hisport = pluto_port; for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next) { DBG(DBG_CONTROLMORE, { ipstr_buf b1; ipstr_buf b2; DBG_log("find_host_pair: comparing %s:%d to %s:%d", ipstr(&p->me.addr, &b1), p->me.host_port, ipstr(&p->him.addr, &b2), p->him.host_port); }); if (sameaddr(&p->me.addr, myaddr) && (!p->me.host_port_specific || p->me.host_port == myport) && sameaddr(&p->him.addr, hisaddr) && (!p->him.host_port_specific || p->him.host_port == hisport) ) { if (prev != NULL) { prev->next = p->next; /* remove p from list */ p->next = host_pairs; /* and stick it on front */ host_pairs = p; } break; } }
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); }
static void klips_process_raw_ifaces(struct raw_iface *rifaces) { struct raw_iface *ifp; /* Find all virtual/real interface pairs. * For each real interface... */ for (ifp = rifaces; ifp != NULL; ifp = ifp->next) { struct raw_iface *v = NULL; /* matching ipsecX interface */ struct raw_iface fake_v; bool after = FALSE; /* has vfp passed ifp on the list? */ bool bad = FALSE; struct raw_iface *vfp; ip_address lip; if (pluto_listen) { err_t e; e = ttoaddr(pluto_listen, 0, 0, &lip); if (e) { DBG_log("invalid listen= option ignored: %s\n", e); pluto_listen = NULL; } } /* ignore if virtual (ipsec*) interface */ if (strncmp(ifp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX) - 1) == 0) continue; /* ignore if virtual (mast*) interface */ if (strncmp(ifp->name, MASTDEVPREFIX, sizeof(MASTDEVPREFIX) - 1) == 0) continue; for (vfp = rifaces; vfp != NULL; vfp = vfp->next) { if (vfp == ifp) { after = TRUE; } else if (sameaddr(&ifp->addr, &vfp->addr)) { /* Different entries with matching IP addresses. * Many interesting cases. */ if (strncmp(vfp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX) - 1) == 0) { if (v != NULL) { loglog(RC_LOG_SERIOUS, "ipsec interfaces %s and %s share same address %s", v->name, vfp->name, ip_str(&ifp->addr)); bad = TRUE; } else { v = vfp; /* current winner */ } } else { /* ugh: a second real interface with the same IP address * "after" allows us to avoid double reporting. */ #if defined(linux) && defined(NETKEY_SUPPORT) if (kern_interface == USE_NETKEY) { if (after) { bad = TRUE; break; } continue; } #endif if (after) { loglog(RC_LOG_SERIOUS, "IP interfaces %s and %s share address %s!", ifp->name, vfp->name, ip_str(&ifp->addr)); } bad = TRUE; } } } if (bad) continue; #if defined(linux) && defined(NETKEY_SUPPORT) if (kern_interface == USE_NETKEY) { v = ifp; goto add_entry; } #endif /* what if we didn't find a virtual interface? */ if (v == NULL) { if (kern_interface == NO_KERNEL) { /* kludge for testing: invent a virtual device */ static const char fvp[] = "virtual"; fake_v = *ifp; passert(sizeof(fake_v.name) > sizeof(fvp)); strcpy(fake_v.name, fvp); addrtot(&ifp->addr, 0, fake_v.name + sizeof(fvp) - 1, sizeof(fake_v.name) - (sizeof(fvp) - 1)); v = &fake_v; } else { DBG(DBG_CONTROL, DBG_log( "IP interface %s %s has no matching ipsec* interface -- ignored", ifp->name, ip_str(&ifp->addr))); continue; } } /* ignore if --listen is specified and we do not match */ if (pluto_listen != NULL) { if (!sameaddr(&lip, &ifp->addr)) { libreswan_log("skipping interface %s with %s", ifp->name, ip_str(&ifp->addr)); continue; } } /* We've got all we need; see if this is a new thing: * search old interfaces list. */ #if defined(linux) && defined(NETKEY_SUPPORT) add_entry: #endif { struct iface_port **p = &interfaces; for (;; ) { struct iface_port *q = *p; struct iface_dev *id = NULL; /* search is over if at end of list */ if (q == NULL) { /* matches nothing -- create a new entry */ int fd = create_socket(ifp, v->name, pluto_port); if (fd < 0) break; DBG(DBG_NATT, DBG_log( "NAT-T KLIPS: checking for nat_traversal_support_non_ike for IPv4")); if (nat_traversal_support_non_ike && addrtypeof(&ifp->addr) == AF_INET) { DBG(DBG_NATT, DBG_log( "NAT-T KLIPS: found, calling nat_traversal_espinudp_socket")); nat_traversal_espinudp_socket( fd, "IPv4", ESPINUDP_WITH_NON_IKE); } else { DBG(DBG_NATT, DBG_log( "NAT-T KLIPS: support not found, nat_traversal_support_non_ike = %s", nat_traversal_support_non_ike ? "TRUE" : "FALSE")); } q = alloc_thing(struct iface_port, "struct iface_port"); id = alloc_thing(struct iface_dev, "struct iface_dev"); LIST_INSERT_HEAD(&interface_dev, id, id_entry); q->ip_dev = id; id->id_rname = clone_str(ifp->name, "real device name"); id->id_vname = clone_str(v->name, "virtual device name klips"); id->id_count++; q->ip_addr = ifp->addr; q->fd = fd; q->next = interfaces; q->change = IFN_ADD; q->port = pluto_port; q->ike_float = FALSE; interfaces = q; libreswan_log( "adding interface %s/%s %s:%d", q->ip_dev->id_vname, q->ip_dev->id_rname, ip_str(&q->ip_addr), q->port); /* * right now, we do not support NAT-T on IPv6, because * the kernel did not support it, and gave an error * it one tried to turn it on. */ if (nat_traversal_support_port_floating && addrtypeof(&ifp->addr) == AF_INET) { DBG(DBG_NATT, DBG_log( "NAT-T KLIPS: found floating port, calling nat_traversal_espinudp_socket")); fd = create_socket(ifp, v->name, pluto_natt_float_port); if (fd < 0) break; nat_traversal_espinudp_socket( fd, "IPv4", ESPINUDP_WITH_NON_ESP); q = alloc_thing( struct iface_port, "struct iface_port"); q->ip_dev = id; id->id_count++; q->ip_addr = ifp->addr; setportof(htons( pluto_natt_float_port), &q->ip_addr); q->port = pluto_natt_float_port; q->fd = fd; q->next = interfaces; q->change = IFN_ADD; q->ike_float = TRUE; interfaces = q; libreswan_log( "adding interface %s/%s %s:%d", q->ip_dev->id_vname, q->ip_dev->id_rname, ip_str(&q-> ip_addr), q->port); } break; } /* search over if matching old entry found */ if (streq(q->ip_dev->id_rname, ifp->name) && streq(q->ip_dev->id_vname, v->name) && sameaddr(&q->ip_addr, &ifp->addr)) { /* matches -- rejuvinate old entry */ q->change = IFN_KEEP; /* look for other interfaces to keep (due to NAT-T) */ for (q = q->next; q; q = q->next) { if (streq(q->ip_dev->id_rname, ifp->name) && streq(q->ip_dev->id_vname, v->name) && sameaddr(&q->ip_addr, &ifp->addr)) q->change = IFN_KEEP; } break; } /* try again */ p = &q->next; } /* for (;;) */ }