int hip_setup_hit_sp_pair(hip_hit_t *src_hit, hip_hit_t *dst_hit, struct in6_addr *src_addr, struct in6_addr *dst_addr, u8 proto, int use_full_prefix, int update) { int so, len, err = 0; u_int prefs, prefd; u8 prefix = (use_full_prefix) ? 128 : HIP_HIT_PREFIX_LEN; int cmd = update ? SADB_X_SPDUPDATE : SADB_X_SPDADD; HIP_DEBUG("\n"); HIP_IFEL(((so = pfkey_open()) < 0), -1, "ERROR in opening pfkey socket: %s\n", ipsec_strerror()); HIP_DEBUG("Adding a pair of SP\n"); HIP_IFEBL((hip_pfkey_policy_modify(so, dst_hit, prefix, src_hit, prefix, src_addr, dst_addr, proto, cmd, IPSEC_DIR_INBOUND)<0), -1, pfkey_close(so), "ERROR in %s the inbound policy\n", update ? "updating" : "adding"); HIP_IFEL(((so = pfkey_open()) < 0), -1, "ERROR in opening pfkey socket: %s\n", ipsec_strerror()); HIP_IFEBL((hip_pfkey_policy_modify(so, src_hit, prefix, dst_hit, prefix, dst_addr, src_addr, proto, cmd, IPSEC_DIR_OUTBOUND)<0), -1, pfkey_close(so), "ERROR in %s the outbound policy\n", update ? "updating" : "adding"); return 0; out_err: return err; }
static int verifypriority(struct sadb_msg *m) { caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_x_policy *xpl; /* check pfkey message. */ if (pfkey_align(m, mhp)) { printf("(%s\n", ipsec_strerror()); return 0; } if (pfkey_check(mhp)) { printf("%s\n", ipsec_strerror()); return 0; } xpl = (struct sadb_x_policy *) mhp[SADB_X_EXT_POLICY]; if (xpl == NULL) { printf("no X_POLICY extension.\n"); return 0; } /* now make sure they match */ if (last_priority != xpl->sadb_x_policy_priority) return 0; return 1; }
int hip_pfkey_policy_modify(int so, hip_hit_t *src_hit, u_int prefs, hip_hit_t *dst_hit, u_int prefd, struct in6_addr *src_addr, struct in6_addr *dst_addr, u8 proto, int cmd, int direction) { int err = 0; struct sockaddr_storage ss_addr, dd_addr, ss_hit, dd_hit; struct sockaddr *s_saddr, *s_shit; struct sockaddr *d_saddr, *d_shit; caddr_t policy = NULL; int policylen = 0; int len = 0; u_int mode; HIP_DEBUG("\n"); // Sanity check HIP_IFEL((src_hit == NULL || dst_hit == NULL), -1, "Invalid hit's\n"); if (src_addr) { // could happen with the delete s_saddr = (struct sockaddr*) &ss_addr; get_sock_addr_from_in6(s_saddr, src_addr); } if (dst_addr) { // could happen with the delete d_saddr = (struct sockaddr*) &dd_addr; get_sock_addr_from_in6(d_saddr, dst_addr); } s_shit = (struct sockaddr*) &ss_hit; get_sock_addr_from_in6(s_shit, src_hit); d_shit = (struct sockaddr*) &dd_hit; get_sock_addr_from_in6(d_shit, dst_hit); if (proto) mode = HIP_IPSEC_DEFAULT_MODE; else mode = IPSEC_MODE_TRANSPORT; HIP_IFEL((getsadbpolicy(&policy, &policylen, direction, s_saddr, d_saddr, mode, cmd)<0), -1, "Error in building the policy\n"); if (cmd == SADB_X_SPDUPDATE) { HIP_IFEL((len = pfkey_send_spdupdate(so, s_shit, prefs, d_shit, prefd, proto, policy, policylen, 0)<0), -1, "libipsec failed send_x4 (%s)\n", ipsec_strerror()); } else if (cmd == SADB_X_SPDADD) { HIP_IFEL((len = pfkey_send_spdadd(so, s_shit, prefs, d_shit, prefd, proto, policy, policylen, 0)<0), -1, "libipsec failed send_x4 (%s)\n", ipsec_strerror()); } else { // SADB_X_SPDDELETE HIP_IFEL((len = pfkey_send_spddelete(so, s_shit, prefs, d_shit, prefd, proto, policy, policylen, 0)<0), -1, "libipsec failed send_x4 (%s)\n", ipsec_strerror()); } return len; out_err: return err; }
void hip_delete_sa(u32 spi, struct in6_addr *peer_addr, struct in6_addr *dst_addr, int direction, hip_ha_t *entry) { int so, len, err = 0; struct sockaddr_storage ss_addr, dd_addr; struct sockaddr *saddr; struct sockaddr *daddr; in_port_t sport, dport; /* @todo: sport and dport should be used! */ if (direction == HIP_SPI_DIRECTION_OUT) { sport = entry->local_udp_port; dport = entry->peer_udp_port; entry->outbound_sa_count--; if (entry->outbound_sa_count < 0) { HIP_ERROR("Warning: out sa count negative\n"); entry->outbound_sa_count = 0; } } else { sport = entry->peer_udp_port; dport = entry->local_udp_port; entry->inbound_sa_count--; if (entry->inbound_sa_count < 0) { HIP_ERROR("Warning: in sa count negative\n"); entry->inbound_sa_count = 0; } } saddr = (struct sockaddr*) &ss_addr; daddr = (struct sockaddr*) &dd_addr; HIP_DEBUG("\n"); HIP_DEBUG("spi=0x%x\n", spi); HIP_DEBUG_IN6ADDR("peer_addr", peer_addr); HIP_DEBUG_IN6ADDR("dst_addr", dst_addr); // Sanity check HIP_IFEL((!peer_addr || !dst_addr), -1, "Addresses not valid when deleting SA's\n"); HIP_IFEL(((so = pfkey_open()) < 0), -1, "ERROR in opening pfkey socket: %s\n", ipsec_strerror()); get_sock_addr_from_in6(saddr, peer_addr); get_sock_addr_from_in6(daddr, dst_addr); HIP_IFEBL(((len = pfkey_send_delete(so, SADB_SATYPE_ESP, HIP_IPSEC_DEFAULT_MODE, saddr, daddr, spi))<0), -1, pfkey_close(so), "ERROR in deleting sa %s", ipsec_strerror()); out_err: return; }
int hip_flush_all_sa() { int so, len, err = 0; HIP_DEBUG("\n"); HIP_IFEL(((so = pfkey_open()) < 0), -1, "ERROR in opening pfkey socket: %s\n", ipsec_strerror()); HIP_DEBUG("Flushing all SA's\n"); HIP_IFEBL(((len = pfkey_send_flush(so, SADB_SATYPE_ESP))<0), -1, pfkey_close(so), "ERROR in flushing policies %s\n", ipsec_strerror()); return len; out_err: return err; }
int hip_flush_all_policy() { int so, len, err = 0; HIP_DEBUG("\n"); HIP_IFEL(((so = pfkey_open()) < 0), -1, "ERROR in opening pfkey socket: %s\n", ipsec_strerror()); HIP_DEBUG("FLushing all SP's\n"); HIP_IFEBL(((len = pfkey_send_spdflush(so))<0), -1, pfkey_close(so), "ERROR in flushing policies %s\n", ipsec_strerror()); HIP_DEBUG("FLushing all SP's was successful\n"); return len; out_err: HIP_ERROR("FLushing all SP's\n"); return err; }
char *setpolicy(char *req) { int len; char *buf; if ((len = ipsec_get_policylen(req)) < 0) { printf("ipsec_get_policylen: %s\n", ipsec_strerror()); return NULL; } if ((buf = malloc(len)) == NULL) { perror("malloc"); return NULL; } if ((len = ipsec_set_policy(buf, len, req)) < 0) { printf("ipsec_set_policy: %s\n", ipsec_strerror()); free(buf); return NULL; } return buf; }
void hip_delete_hit_sp_pair(hip_hit_t *src_hit, hip_hit_t *dst_hit, u8 proto, int use_full_prefix) { int so, len, err = 0; u8 prefix = (use_full_prefix) ? 128 : HIP_HIT_PREFIX_LEN; HIP_DEBUG("\n"); HIP_IFEL(((so = pfkey_open()) < 0), -1, "ERROR in opening pfkey socket: %s\n", ipsec_strerror()); HIP_IFEBL((hip_pfkey_policy_modify(so, dst_hit, prefix, src_hit, prefix, NULL, NULL, proto, SADB_X_SPDDELETE, IPSEC_DIR_INBOUND)<0), -1, pfkey_close(so), "ERROR in deleting the inbound policy\n"); HIP_IFEL(((so = pfkey_open()) < 0), -1, "ERROR in opening pfkey socket: %s\n", ipsec_strerror()); HIP_IFEBL((hip_pfkey_policy_modify(so, src_hit, prefix, dst_hit, prefix, NULL, NULL, proto, SADB_X_SPDDELETE, IPSEC_DIR_OUTBOUND)<0), -1, pfkey_close(so), "ERROR in deleting the outbound policy\n"); out_err: return; }
int test(char *policy, int family) { int so, proto, optname; int len; char getbuf[1024]; switch (family) { case PF_INET: proto = IPPROTO_IP; optname = IP_IPSEC_POLICY; break; case PF_INET6: proto = IPPROTO_IPV6; optname = IPV6_IPSEC_POLICY; break; } if ((so = socket(family, SOCK_DGRAM, 0)) < 0) perror("socket"); if (setsockopt(so, proto, optname, policy, PFKEY_EXTLEN(policy)) < 0) perror("setsockopt"); len = sizeof(getbuf); memset(getbuf, 0, sizeof(getbuf)); if (getsockopt(so, proto, optname, getbuf, &len) < 0) perror("getsockopt"); { char *buf = NULL; printf("\tgetlen:%d\n", len); if ((buf = ipsec_dump_policy(getbuf, NULL)) == NULL) ipsec_strerror(); else printf("\t[%s]\n", buf); free(buf); } close (so); }
static void sock4_open(struct flags *flags #ifdef IPSEC_POLICY_IPSEC , char *policy #endif /* IPSEC_POLICY_IPSEC */ ) { #ifdef IPSEC #ifndef IPSEC_POLICY_IPSEC int optval; #endif #endif if (with_v4dest == 0) return; if ((s4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { syslog(LOG_ERR, "<%s> socket(v4): %s", __func__, strerror(errno)); exit(1); } #if 0 /* XXX: not necessary ?? */ /* * join all routers multicast addresses. */ some_join_function(); #endif #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC if (flags->policy) { char *buf; buf = ipsec_set_policy(policy, strlen(policy)); if (buf == NULL) errx(1, "%s", ipsec_strerror()); /* XXX should handle in/out bound policy. */ if (setsockopt(s4, IPPROTO_IP, IP_IPSEC_POLICY, buf, ipsec_get_policylen(buf)) < 0) err(1, "setsockopt(IP_IPSEC_POLICY)"); free(buf); } #else /* IPSEC_POLICY_IPSEC */ if (flags->auth) { optval = IPSEC_LEVEL_REQUIRE; if (setsockopt(s4, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, &optval, sizeof(optval)) == -1) { syslog(LOG_ERR, "<%s> IP_AUTH_TRANS_LEVEL: %s", __func__, strerror(errno)); exit(1); } } if (flags->encrypt) { optval = IPSEC_LEVEL_REQUIRE; if (setsockopt(s4, IPPROTO_IP, IP_ESP_TRANS_LEVEL, &optval, sizeof(optval)) == -1) { syslog(LOG_ERR, "<%s> IP_ESP_TRANS_LEVEL: %s", __func__, strerror(errno)); exit(1); } } #endif /* IPSEC_POLICY_IPSEC */ #endif /* IPSEC */ return; }
static void sock6_open(struct flags *flags #ifdef IPSEC_POLICY_IPSEC , char *policy #endif /* IPSEC_POLICY_IPSEC */ ) { struct icmp6_filter filt; int on; #ifdef IPSEC #ifndef IPSEC_POLICY_IPSEC int optval; #endif #endif if (with_v6dest == 0) return; if (with_v6dest && (s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { syslog(LOG_ERR, "<%s> socket(v6): %s", __func__, strerror(errno)); exit(1); } /* * join all routers multicast addresses. */ #if 0 /* XXX: not necessary ?? */ join_multi(LL_ALLROUTERS); join_multi(SL_ALLROUTERS); #endif /* set icmpv6 filter */ ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); if (setsockopt(s6, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) { syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", __func__, strerror(errno)); exit(1); } /* specify to tell receiving interface */ on = 1; if (setsockopt(s6, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", __func__, strerror(errno)); exit(1); } #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC if (flags->policy) { char *buf; buf = ipsec_set_policy(policy, strlen(policy)); if (buf == NULL) errx(1, "%s", ipsec_strerror()); /* XXX should handle in/out bound policy. */ if (setsockopt(s6, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, ipsec_get_policylen(buf)) < 0) err(1, "setsockopt(IPV6_IPSEC_POLICY)"); free(buf); } #else /* IPSEC_POLICY_IPSEC */ if (flags->auth) { optval = IPSEC_LEVEL_REQUIRE; if (setsockopt(s6, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &optval, sizeof(optval)) == -1) { syslog(LOG_ERR, "<%s> IPV6_AUTH_TRANS_LEVEL: %s", __func__, strerror(errno)); exit(1); } } if (flags->encrypt) { optval = IPSEC_LEVEL_REQUIRE; if (setsockopt(s6, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &optval, sizeof(optval)) == -1) { syslog(LOG_ERR, "<%s> IPV6_ESP_TRANS_LEVEL: %s", __func__, strerror(errno)); exit(1); } } #endif /* IPSEC_POLICY_IPSEC */ #endif /* IPSEC */ return; }
/* start l2tpd listner */ static int l2tpd_listener_start(l2tpd_listener *_this) { l2tpd *_l2tpd; int af, lvl, opt, sock, ival; char hbuf[NI_MAXHOST + NI_MAXSERV + 16]; _l2tpd = _this->self; sock = -1; af = _this->bind.sin6.sin6_family; lvl = (af == AF_INET)? IPPROTO_IP : IPPROTO_IPV6; if (_this->tun_name[0] == '\0') strlcpy(_this->tun_name, L2TPD_DEFAULT_LAYER2_LABEL, sizeof(_this->tun_name)); if ((sock = socket(_this->bind.sin6.sin6_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP)) < 0) { l2tpd_log(_l2tpd, LOG_ERR, "socket() failed in %s(): %m", __func__); goto fail; } #if defined(IP_STRICT_RCVIF) && defined(USE_STRICT_RCVIF) ival = 1; if (setsockopt(sock, IPPROTO_IP, IP_STRICT_RCVIF, &ival, sizeof(ival)) != 0) l2tpd_log(_l2tpd, LOG_WARNING, "%s(): setsockopt(IP_STRICT_RCVIF) failed: %m", __func__); #endif ival = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &ival, sizeof(ival)) != 0) { l2tpd_log(_l2tpd, LOG_ERR, "setsockopt(,,SO_REUSEPORT) failed in %s(): %m", __func__); goto fail; } if (bind(sock, (struct sockaddr *)&_this->bind, _this->bind.sin6.sin6_len) != 0) { l2tpd_log(_l2tpd, LOG_ERR, "Binding %s/udp: %m", addrport_tostring((struct sockaddr *)&_this->bind, _this->bind.sin6.sin6_len, hbuf, sizeof(hbuf))); goto fail; } #ifdef USE_LIBSOCKUTIL if (setsockoptfromto(sock) != 0) { l2tpd_log(_l2tpd, LOG_ERR, "setsockoptfromto() failed in %s(): %m", __func__); goto fail; } #else opt = (af == AF_INET)? IP_RECVDSTADDR : IPV6_RECVPKTINFO; ival = 1; if (setsockopt(sock, lvl, opt, &ival, sizeof(ival)) != 0) { l2tpd_log(_l2tpd, LOG_ERR, "setsockopt(,,IP{,V6}_RECVDSTADDR) failed in %s(): %m", __func__); goto fail; } #endif #ifdef USE_SA_COOKIE if (af == AF_INET) { ival = 1; if (setsockopt(sock, IPPROTO_IP, IP_IPSECFLOWINFO, &ival, sizeof(ival)) != 0) { l2tpd_log(_l2tpd, LOG_ERR, "setsockopt(,,IP_IPSECFLOWINFO) failed in %s(): %m", __func__); goto fail; } } #endif #ifdef IP_PIPEX opt = (af == AF_INET)? IP_PIPEX : IPV6_PIPEX; ival = 1; if (setsockopt(sock, lvl, opt, &ival, sizeof(ival)) != 0) l2tpd_log(_l2tpd, LOG_WARNING, "%s(): setsockopt(IP{,V6}_PIPEX) failed: %m", __func__); #endif if (_this->conf->require_ipsec) { #ifdef IP_IPSEC_POLICY caddr_t ipsec_policy_in, ipsec_policy_out; opt = (af == AF_INET)? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY; /* * Note: ipsec_set_policy() will assign the buffer for * yacc parser stack, however it never free. * it cause memory leak (-2000byte). */ if ((ipsec_policy_in = ipsec_set_policy(L2TPD_IPSEC_POLICY_IN, strlen(L2TPD_IPSEC_POLICY_IN))) == NULL) { l2tpd_log(_l2tpd, LOG_ERR, "ipsec_set_policy(L2TPD_IPSEC_POLICY_IN) failed " "at %s(): %s: %m", __func__, ipsec_strerror()); } else if (setsockopt(sock, lvl, opt, ipsec_policy_in, ipsec_get_policylen(ipsec_policy_in)) < 0) { l2tpd_log(_l2tpd, LOG_WARNING, "setsockopt(,,IP_IPSEC_POLICY(in)) failed " "in %s(): %m", __func__); } if ((ipsec_policy_out = ipsec_set_policy(L2TPD_IPSEC_POLICY_OUT, strlen(L2TPD_IPSEC_POLICY_OUT))) == NULL) { l2tpd_log(_l2tpd, LOG_ERR, "ipsec_set_policy(L2TPD_IPSEC_POLICY_OUT) failed " "at %s(): %s: %m", __func__, ipsec_strerror()); } if (ipsec_policy_out != NULL && setsockopt(sock, lvl, opt, ipsec_policy_out, ipsec_get_policylen(ipsec_policy_out)) < 0) { l2tpd_log(_l2tpd, LOG_WARNING, "setsockopt(,,IP_IPSEC_POLICY(out)) failed " "in %s(): %m", __func__); } free(ipsec_policy_in); free(ipsec_policy_out); #elif defined(IP_ESP_TRANS_LEVEL) opt = (af == AF_INET) ? IP_ESP_TRANS_LEVEL : IPV6_ESP_TRANS_LEVEL; ival = IPSEC_LEVEL_REQUIRE; if (setsockopt(sock, lvl, opt, &ival, sizeof(ival)) != 0) { l2tpd_log(_l2tpd, LOG_WARNING, "setsockopt(,,IP{,V6}_ESP_TRANS_LEVEL(out)) failed " "in %s(): %m", __func__); } #else #error IP_IPSEC_POLICY or IP_ESP_TRANS_LEVEL must be usable. #endif } _this->sock = sock; event_set(&_this->ev_sock, _this->sock, EV_READ | EV_PERSIST, l2tpd_io_event, _this); event_add(&_this->ev_sock, NULL); l2tpd_log(_l2tpd, LOG_INFO, "Listening %s/udp (L2TP LNS) [%s]", addrport_tostring((struct sockaddr *)&_this->bind, _this->bind.sin6.sin6_len, hbuf, sizeof(hbuf)), _this->tun_name); return 0; fail: if (sock >= 0) close(sock); return 1; }
void pfkey_spdump(struct sadb_msg *m) { char pbuf[NI_MAXSERV]; caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_address *m_saddr, *m_daddr; struct sadb_x_policy *m_xpl; struct sadb_lifetime *m_lft = NULL; struct sockaddr *sa; u_int16_t port; /* check pfkey message. */ if (pfkey_align(m, mhp)) { printf("%s\n", ipsec_strerror()); return; } if (pfkey_check(mhp)) { printf("%s\n", ipsec_strerror()); return; } m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; m_xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; m_lft = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; /* source address */ if (m_saddr == NULL) { printf("no ADDRESS_SRC extension.\n"); return; } sa = (struct sockaddr *)(m_saddr + 1); switch (sa->sa_family) { case AF_INET: case AF_INET6: if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0) port = 0; /*XXX*/ else port = atoi(pbuf); printf("%s%s ", str_ipaddr(sa), str_prefport(sa->sa_family, m_saddr->sadb_address_prefixlen, port)); break; default: printf("unknown-af "); break; } /* destination address */ if (m_daddr == NULL) { printf("no ADDRESS_DST extension.\n"); return; } sa = (struct sockaddr *)(m_daddr + 1); switch (sa->sa_family) { case AF_INET: case AF_INET6: if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0) port = 0; /*XXX*/ else port = atoi(pbuf); printf("%s%s ", str_ipaddr(sa), str_prefport(sa->sa_family, m_daddr->sadb_address_prefixlen, port)); break; default: printf("unknown-af "); break; } /* upper layer protocol */ if (m_saddr->sadb_address_proto != m_daddr->sadb_address_proto) { printf("upper layer protocol mismatched.\n"); return; } if (m_saddr->sadb_address_proto == IPSEC_ULPROTO_ANY) printf("any"); else GETMSGSTR(str_upper, m_saddr->sadb_address_proto); /* policy */ { char *d_xpl; if (m_xpl == NULL) { printf("no X_POLICY extension.\n"); return; } d_xpl = ipsec_dump_policy((char *)m_xpl, "\n\t"); /* dump SPD */ printf("\n\t%s\n", d_xpl); free(d_xpl); } /* lifetime */ if (m_lft) { printf("\tlifetime:%lu validtime:%lu\n", (u_long)m_lft->sadb_lifetime_addtime, (u_long)m_lft->sadb_lifetime_usetime); } printf("\tspid=%ld seq=%ld pid=%ld\n", (u_long)m_xpl->sadb_x_policy_id, (u_long)m->sadb_msg_seq, (u_long)m->sadb_msg_pid); /* XXX TEST */ printf("\trefcnt=%u\n", m->sadb_msg_reserved); return; }
/* * dump SADB_MSG formated. For debugging, you should use kdebug_sadb(). */ void pfkey_sadump(struct sadb_msg *m) { caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_sa *m_sa; struct sadb_x_sa2 *m_sa2; struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts; struct sadb_address *m_saddr, *m_daddr; struct sadb_key *m_auth, *m_enc; /* check pfkey message. */ if (pfkey_align(m, mhp)) { printf("%s\n", ipsec_strerror()); return; } if (pfkey_check(mhp)) { printf("%s\n", ipsec_strerror()); return; } m_sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; m_sa2 = (struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2]; m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; m_lfts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; m_auth = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH]; m_enc = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT]; /* source address */ if (m_saddr == NULL) { printf("no ADDRESS_SRC extension.\n"); return; } printf("%s ", str_ipaddr((struct sockaddr *)(m_saddr + 1))); /* destination address */ if (m_daddr == NULL) { printf("no ADDRESS_DST extension.\n"); return; } printf("%s ", str_ipaddr((struct sockaddr *)(m_daddr + 1))); /* SA type */ if (m_sa == NULL) { printf("no SA extension.\n"); return; } if (m_sa2 == NULL) { printf("no SA2 extension.\n"); return; } printf("\n\t"); GETMSGSTR(str_satype, m->sadb_msg_satype); printf("mode="); GETMSGSTR(str_mode, m_sa2->sadb_x_sa2_mode); printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n", (u_int32_t)ntohl(m_sa->sadb_sa_spi), (u_int32_t)ntohl(m_sa->sadb_sa_spi), (u_int32_t)m_sa2->sadb_x_sa2_reqid, (u_int32_t)m_sa2->sadb_x_sa2_reqid); /* encryption key */ if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { printf("\tC: "); GETMSGV2S(str_alg_comp, m_sa->sadb_sa_encrypt); } else if (m->sadb_msg_satype == SADB_SATYPE_ESP) { if (m_enc != NULL) { printf("\tE: "); GETMSGV2S(str_alg_enc, m_sa->sadb_sa_encrypt); ipsec_hexdump((caddr_t)m_enc + sizeof(*m_enc), m_enc->sadb_key_bits / 8); printf("\n"); } } /* authentication key */ if (m_auth != NULL) { printf("\tA: "); GETMSGV2S(str_alg_auth, m_sa->sadb_sa_auth); ipsec_hexdump((caddr_t)m_auth + sizeof(*m_auth), m_auth->sadb_key_bits / 8); printf("\n"); } /* replay windoe size & flags */ printf("\tseq=0x%08x replay=%u flags=0x%08x ", m_sa2->sadb_x_sa2_sequence, m_sa->sadb_sa_replay, m_sa->sadb_sa_flags); /* state */ printf("state="); GETMSGSTR(str_state, m_sa->sadb_sa_state); printf("\n"); /* lifetime */ if (m_lftc != NULL) { time_t tmp_time = time(0); printf("\tcreated: %s", str_time(m_lftc->sadb_lifetime_addtime)); printf("\tcurrent: %s\n", str_time(tmp_time)); printf("\tdiff: %lu(s)", (u_long)(m_lftc->sadb_lifetime_addtime == 0 ? 0 : (tmp_time - m_lftc->sadb_lifetime_addtime))); printf("\thard: %lu(s)", (u_long)(m_lfth == NULL ? 0 : m_lfth->sadb_lifetime_addtime)); printf("\tsoft: %lu(s)\n", (u_long)(m_lfts == NULL ? 0 : m_lfts->sadb_lifetime_addtime)); printf("\tlast: %s", str_time(m_lftc->sadb_lifetime_usetime)); printf("\thard: %lu(s)", (u_long)(m_lfth == NULL ? 0 : m_lfth->sadb_lifetime_usetime)); printf("\tsoft: %lu(s)\n", (u_long)(m_lfts == NULL ? 0 : m_lfts->sadb_lifetime_usetime)); str_lifetime_byte(m_lftc, "current"); str_lifetime_byte(m_lfth, "hard"); str_lifetime_byte(m_lfts, "soft"); printf("\n"); printf("\tallocated: %lu", (unsigned long)m_lftc->sadb_lifetime_allocations); printf("\thard: %lu", (u_long)(m_lfth == NULL ? 0 : m_lfth->sadb_lifetime_allocations)); printf("\tsoft: %lu\n", (u_long)(m_lfts == NULL ? 0 : m_lfts->sadb_lifetime_allocations)); } printf("\tsadb_seq=%lu pid=%lu ", (u_long)m->sadb_msg_seq, (u_long)m->sadb_msg_pid); /* XXX DEBUG */ printf("refcnt=%u\n", m->sadb_msg_reserved); return; }
int main(int argc, char **argv) { FILE *fp = stdin; int c; if (argc == 1) { usage(0); } thiszone = gmt2local(0); while ((c = getopt(argc, argv, "acdf:HlnvxDFPphVrk?")) != -1) { switch (c) { case 'c': f_mode = MODE_STDIN; #ifdef HAVE_READLINE /* disable filename completion */ rl_bind_key('\t', rl_insert); #endif break; case 'f': f_mode = MODE_SCRIPT; if (strcmp(optarg, "-") == 0) { fp = stdin; } else if ((fp = fopen(optarg, "r")) == NULL) { err(1, "Can't open `%s'", optarg); } break; case 'D': f_mode = MODE_CMDDUMP; break; case 'F': f_mode = MODE_CMDFLUSH; break; case 'a': f_all = 1; break; case 'l': f_forever = 1; break; case 'n': f_notreally = 1; break; #ifdef __NetBSD__ case 'h': #endif case 'H': f_hexdump = 1; break; case 'x': f_mode = MODE_PROMISC; f_tflag++; break; case 'P': f_policy = 1; break; case 'p': f_withports = 1; break; case 'v': f_verbose = 1; break; case 'r': #ifdef HAVE_POLICY_FWD f_rfcmode = 1; #else rkwarn(); #endif break; case 'k': #ifdef HAVE_POLICY_FWD f_rfcmode = 0; #else rkwarn(); #endif break; case 'V': usage(1); break; #ifndef __NetBSD__ case 'h': #endif case '?': default: usage(0); } } argc -= optind; argv += optind; if (argc > 0) { while (argc--) { if (fileproc(*argv++) < 0) { err(1, "%s", argv[-1]); } } exit(0); } so = pfkey_open(); if (so < 0) { perror("pfkey_open"); exit(1); } switch (f_mode) { case MODE_CMDDUMP: sendkeyshort(f_policy ? SADB_X_SPDDUMP : SADB_DUMP); break; case MODE_CMDFLUSH: sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH); break; case MODE_SCRIPT: if (get_supported() < 0) { errx(1, "%s", ipsec_strerror()); } if (parse(&fp)) exit(1); break; case MODE_STDIN: if (get_supported() < 0) { errx(1, "%s", ipsec_strerror()); } stdin_loop(); break; case MODE_PROMISC: promisc(); /* NOTREACHED */ default: usage(0); } exit(0); }
/* Security associations in the kernel with BEET are bounded to the outer * address, meaning IP addresses. As a result the parameters to be given * should be such an addresses and not the HITs. */ uint32_t hip_add_sa(struct in6_addr *saddr, struct in6_addr *daddr, struct in6_addr *src_hit, struct in6_addr *dst_hit, uint32_t spi, int ealg, struct hip_crypto_key *enckey, struct hip_crypto_key *authkey, int already_acquired, int direction, int update, hip_ha_t *entry) { int so, len, err = 0, e_keylen, a_keylen; int aalg = ealg; u_int wsize = 4; /* XXX static size of window */ struct sockaddr_storage ss_addr, dd_addr; struct sockaddr *s_saddr; struct sockaddr *d_saddr; uint32_t reqid = 0; u_int32_t seq = 0; u_int flags = 0; // always zero u_int64_t lifebyte = 0, lifetime = 0; //u_int8_t l_natt_type = HIP_UDP_ENCAP_ESPINUDP_NON_IKE; u_int8_t l_natt_type = HIP_UDP_ENCAP_ESPINUDP; // FIXME: this parameter maybe should be related to some esp parameters (according to racoon source code) u_int16_t l_natt_frag = 0; /* Mappings from HIP to PFKEY algo names */ u_int e_types[] = {SADB_EALG_NULL, SADB_X_EALG_AESCBC, SADB_EALG_3DESCBC, SADB_EALG_3DESCBC, SADB_X_EALG_BLOWFISHCBC, SADB_EALG_NULL, SADB_EALG_NULL}; u_int a_algos[] = {SADB_AALG_NONE, SADB_AALG_SHA1HMAC, SADB_AALG_SHA1HMAC, SADB_AALG_MD5HMAC, SADB_AALG_SHA1HMAC, SADB_AALG_SHA1HMAC, SADB_AALG_MD5HMAC}; u_int e_type = e_types[ealg]; u_int a_type = a_algos[aalg]; in_port_t sport = entry->local_udp_port; in_port_t dport = entry->peer_udp_port; a_keylen = hip_auth_key_length_esp(ealg); e_keylen = hip_enc_key_length(ealg); get_random_bytes(&reqid, sizeof(uint32_t)); get_random_bytes(&seq, sizeof(uint32_t)); HIP_DEBUG("\n"); HIP_DEBUG_HIT("src_hit", src_hit); HIP_DEBUG_HIT("dst_hit", dst_hit); HIP_DEBUG_IN6ADDR("saddr", saddr); HIP_DEBUG_IN6ADDR("daddr", daddr); HIP_IFEL((!saddr || !daddr), 1, "Addresses not valid when adding SA's\n"); HIP_IFEL(((so = pfkey_open()) < 0), 1, "ERROR in opening pfkey socket: %s\n", ipsec_strerror()); s_saddr = (struct sockaddr*) &ss_addr; d_saddr = (struct sockaddr*) &dd_addr; get_sock_addr_from_in6(s_saddr, saddr); get_sock_addr_from_in6(d_saddr, daddr); if (direction == HIP_SPI_DIRECTION_OUT) { entry->outbound_sa_count++; } else { entry->inbound_sa_count++; } // NOTE: port numbers remains in host representation if (update) { if (sport) { // pfkey_send_update_nat when update = 1 and sport != 0 HIP_IFEBL(((len = pfkey_send_update_nat(so, SADB_SATYPE_ESP, HIP_IPSEC_DEFAULT_MODE, s_saddr, d_saddr, spi, reqid, wsize, (void*) enckey, e_type, e_keylen, a_type, a_keylen, flags, 0, lifebyte, lifetime, 0, seq, l_natt_type, sport, dport, NULL, l_natt_frag)) < 0), 1, pfkey_close(so), "ERROR in updating sa for nat: %s\n", ipsec_strerror()); } else { // pfkey_send_update when update = 1 and sport == 0 HIP_IFEBL(((len = pfkey_send_update(so, SADB_SATYPE_ESP, HIP_IPSEC_DEFAULT_MODE, s_saddr, d_saddr, spi, reqid, wsize, (void*) enckey, e_type, e_keylen, a_type, a_keylen, flags, 0, lifebyte, lifetime, 0, seq)) < 0), 1, pfkey_close(so), "ERROR in updating sa: %s\n", ipsec_strerror()); } } else { if (sport) { // pfkey_send_add_nat when update = 0 and sport != 0 HIP_IFEBL(((len = pfkey_send_add_nat(so, SADB_SATYPE_ESP, HIP_IPSEC_DEFAULT_MODE, s_saddr, d_saddr, spi, reqid, wsize, (void*) enckey, e_type, e_keylen, a_type, a_keylen, flags, 0, lifebyte, lifetime, 0, seq, l_natt_type, sport, dport, NULL, l_natt_frag)) < 0), 1, pfkey_close(so), "ERROR in adding sa for nat: %s\n", ipsec_strerror()); } else { // pfkey_send_add when update = 0 and sport == 0 HIP_IFEBL(((len = pfkey_send_add(so, SADB_SATYPE_ESP, HIP_IPSEC_DEFAULT_MODE, s_saddr, d_saddr, spi, reqid, wsize, (void*) enckey, e_type, e_keylen, a_type, a_keylen, flags, 0, lifebyte, lifetime, 0, seq)) < 0), 1, pfkey_close(so), "ERROR in adding sa: %s\n", ipsec_strerror()); } } return 0; out_err: return err; }