/* * Verify that the skb can go out on this ipsp. * Return 0 if OK, error code otherwise. */ static int ipsec_mast_check_outbound_policy(struct ipsec_xmit_state *ixs) { int failed_outbound_check = 0; struct ipsec_sa *ipsp = ixs->ipsp; if (!ixs || !ixs->ipsp || !ixs->iph) return -EFAULT; /* Note: "xor" (^) logically replaces "not equal" * (!=) and "bitwise or" (|) logically replaces * "boolean or" (||). This is done to speed up * execution by doing only bitwise operations and * no branch operations */ if (osw_ip_hdr_version(ixs) == 4) { struct iphdr *ipp = osw_ip4_hdr(ixs); if (ip_address_family(&ipsp->ips_said.dst) != AF_INET) { failed_outbound_check = 1; } else if (((ipp->saddr & ipsp->ips_mask_s.u.v4.sin_addr.s_addr) ^ ipsp->ips_flow_s.u.v4.sin_addr.s_addr) | ((ipp->daddr & ipsp->ips_mask_d.u.v4.sin_addr.s_addr) ^ ipsp->ips_flow_d.u.v4.sin_addr.s_addr)) { failed_outbound_check = 1; } } else if (osw_ip_hdr_version(ixs) == 6) { struct ipv6hdr *ipp6 = osw_ip6_hdr(ixs); if (ip_address_family(&ipsp->ips_said.dst) != AF_INET6) { failed_outbound_check = 1; } else if (((ipp6->saddr.s6_addr32[0] & ipsp->ips_mask_s.u.v6.sin6_addr.s6_addr32[0]) ^ ipsp->ips_flow_s.u.v6.sin6_addr.s6_addr32[0]) | ((ipp6->daddr.s6_addr32[0] & ipsp->ips_mask_d.u.v6.sin6_addr.s6_addr32[0]) ^ ipsp->ips_flow_d.u.v6.sin6_addr.s6_addr32[0])) { failed_outbound_check = 1; } else if (((ipp6->saddr.s6_addr32[1] & ipsp->ips_mask_s.u.v6.sin6_addr.s6_addr32[1]) ^ ipsp->ips_flow_s.u.v6.sin6_addr.s6_addr32[1]) | ((ipp6->daddr.s6_addr32[1] & ipsp->ips_mask_d.u.v6.sin6_addr.s6_addr32[1]) ^ ipsp->ips_flow_d.u.v6.sin6_addr.s6_addr32[1])) { failed_outbound_check = 1; } else if (((ipp6->saddr.s6_addr32[2] & ipsp->ips_mask_s.u.v6.sin6_addr.s6_addr32[2]) ^ ipsp->ips_flow_s.u.v6.sin6_addr.s6_addr32[2]) | ((ipp6->daddr.s6_addr32[2] & ipsp->ips_mask_d.u.v6.sin6_addr.s6_addr32[2]) ^ ipsp->ips_flow_d.u.v6.sin6_addr.s6_addr32[2])) { failed_outbound_check = 1; } else if (((ipp6->saddr.s6_addr32[3] & ipsp->ips_mask_s.u.v6.sin6_addr.s6_addr32[3]) ^ ipsp->ips_flow_s.u.v6.sin6_addr.s6_addr32[3]) | ((ipp6->daddr.s6_addr32[3] & ipsp->ips_mask_d.u.v6.sin6_addr.s6_addr32[3]) ^ ipsp->ips_flow_d.u.v6.sin6_addr.s6_addr32[3])) { failed_outbound_check = 1; } } if (failed_outbound_check) { char saddr_txt[ADDRTOA_BUF], daddr_txt[ADDRTOA_BUF]; char sflow_txt[SUBNETTOA_BUF], dflow_txt[SUBNETTOA_BUF]; if (ipsp->ips_flow_s.u.v4.sin_family == AF_INET6) { subnet6toa(&ipsp->ips_flow_s.u.v6.sin6_addr, &ipsp->ips_mask_s.u.v6.sin6_addr, 0, sflow_txt, sizeof(sflow_txt)); subnet6toa(&ipsp->ips_flow_d.u.v6.sin6_addr, &ipsp->ips_mask_d.u.v6.sin6_addr, 0, dflow_txt, sizeof(dflow_txt)); inet_addrtot(AF_INET6, &osw_ip6_hdr(ixs)->saddr, 0, saddr_txt, sizeof(saddr_txt)); inet_addrtot(AF_INET6, &osw_ip6_hdr(ixs)->daddr, 0, daddr_txt, sizeof(daddr_txt)); } else { subnettoa(ipsp->ips_flow_s.u.v4.sin_addr, ipsp->ips_mask_s.u.v4.sin_addr, 0, sflow_txt, sizeof(sflow_txt)); subnettoa(ipsp->ips_flow_d.u.v4.sin_addr, ipsp->ips_mask_d.u.v4.sin_addr, 0, dflow_txt, sizeof(dflow_txt)); inet_addrtot(AF_INET, &osw_ip4_hdr(ixs)->saddr, 0, saddr_txt, sizeof(saddr_txt)); inet_addrtot(AF_INET, &osw_ip4_hdr(ixs)->daddr, 0, daddr_txt, sizeof(daddr_txt)); } if (!ixs->sa_len) ixs->sa_len = KLIPS_SATOT(debug_mast, &ixs->outgoing_said, 0, ixs->sa_txt, sizeof(ixs->sa_txt)); KLIPS_PRINT(debug_mast, "klips_debug:ipsec_mast_check_outbound_policy: " "SA:%s, inner tunnel policy [%s -> %s] does not agree with pkt contents [%s -> %s].\n", ixs->sa_len ? ixs->sa_txt : " (error)", sflow_txt, dflow_txt, saddr_txt, daddr_txt); if(ixs->stats) ixs->stats->rx_dropped++; return -EACCES; } #if 0 { char sflow_txt[SUBNETTOA_BUF], dflow_txt[SUBNETTOA_BUF]; char saddr_txt[ADDRTOA_BUF], daddr_txt[ADDRTOA_BUF]; struct in_addr ipaddr; subnettoa(ixs->ipsp->ips_flow_s.u.v4.sin_addr, ixs->ipsp->ips_mask_s.u.v4.sin_addr, 0, sflow_txt, sizeof(sflow_txt)); subnettoa(ixs->ipsp->ips_flow_d.u.v4.sin_addr, ixs->ipsp->ips_mask_d.u.v4.sin_addr, 0, dflow_txt, sizeof(dflow_txt)); ipaddr.s_addr = ixs->iph->saddr; addrtoa(ipaddr, 0, saddr_txt, sizeof(saddr_txt)); ipaddr.s_addr = ixs->iph->daddr; addrtoa(ipaddr, 0, daddr_txt, sizeof(daddr_txt)); if (!ixs->sa_len) ixs->sa_len = KLIPS_SATOT(debug_mast, &ixs->outgoing_said, 0, ixs->sa_txt, sizeof(ixs->sa_txt)); KLIPS_PRINT(debug_mast, "klips_debug:ipsec_mast_check_outbound_policy: " "SA:%s, inner tunnel policy [%s -> %s] agrees with pkt contents [%s -> %s].\n", ixs->sa_len ? ixs->sa_txt : " (error)", sflow_txt, dflow_txt, saddr_txt, daddr_txt); } #endif return 0; }
IPSEC_PROCFS_DEBUG_NO_STATIC int ipsec_spi_format(struct ipsec_sa *sa_p, struct seq_file *seq) { char sa[SATOT_BUF]; char buf_s[SUBNETTOA_BUF]; char buf_d[SUBNETTOA_BUF]; size_t sa_len; ipsec_sa_get(sa_p, IPSEC_REFPROC); sa_len = satot(&sa_p->ips_said, 'x', sa, sizeof(sa)); seq_printf(seq, "%s ", sa_len ? sa : " (error)"); seq_printf(seq, "%s%s%s", IPS_XFORM_NAME(sa_p)); seq_printf(seq, ": dir=%s", (sa_p->ips_flags & EMT_INBOUND) ? "in " : "out"); if (sa_p->ips_addr_s) { sin_addrtot(sa_p->ips_addr_s, 0, buf_s, sizeof(buf_s)); seq_printf(seq, " src=%s", buf_s); } if ((sa_p->ips_said.proto == IPPROTO_IPIP) && (sa_p->ips_flags & (SADB_X_SAFLAGS_INFLOW |SADB_X_SAFLAGS_POLICYONLY))) { if (sa_p->ips_flow_s.u.v4.sin_family == AF_INET) { subnettoa(sa_p->ips_flow_s.u.v4.sin_addr, sa_p->ips_mask_s.u.v4.sin_addr, 0, buf_s, sizeof(buf_s)); subnettoa(sa_p->ips_flow_d.u.v4.sin_addr, sa_p->ips_mask_d.u.v4.sin_addr, 0, buf_d, sizeof(buf_d)); } else { subnet6toa(&sa_p->ips_flow_s.u.v6.sin6_addr, &sa_p->ips_mask_s.u.v6.sin6_addr, 0, buf_s, sizeof(buf_s)); subnet6toa(&sa_p->ips_flow_d.u.v6.sin6_addr, &sa_p->ips_mask_d.u.v6.sin6_addr, 0, buf_d, sizeof(buf_d)); } seq_printf(seq, " policy=%s->%s", buf_s, buf_d); } if (sa_p->ips_iv_bits) { int j; seq_printf(seq, " iv_bits=%dbits iv=0x", sa_p->ips_iv_bits); for (j = 0; j < sa_p->ips_iv_bits / 8; j++) { #ifdef CONFIG_KLIPS_OCF if (sa_p->ips_iv == NULL) { /* * ocf doesn't set the IV * so fake it for the test cases */ seq_printf(seq, "%02x", 0xA5 + j); } else #endif seq_printf(seq, "%02x", ((__u8*)sa_p->ips_iv)[j]); } } if (sa_p->ips_encalg || sa_p->ips_authalg) { if (sa_p->ips_replaywin) seq_printf(seq, " ooowin=%d", sa_p->ips_replaywin); if (sa_p->ips_errs.ips_replaywin_errs) seq_printf(seq, " ooo_errs=%d", sa_p->ips_errs.ips_replaywin_errs); if (sa_p->ips_replaywin_lastseq) seq_printf(seq, " seq=%d", sa_p->ips_replaywin_lastseq); if (sa_p->ips_replaywin_bitmap) seq_printf(seq, " bit=0x%Lx", sa_p->ips_replaywin_bitmap); if (sa_p->ips_replaywin_maxdiff) seq_printf(seq, " max_seq_diff=%d", sa_p->ips_replaywin_maxdiff); } if (sa_p->ips_flags & ~EMT_INBOUND) { seq_printf(seq, " flags=0x%x", sa_p->ips_flags & ~EMT_INBOUND); seq_printf(seq, "<"); /* flag printing goes here */ seq_printf(seq, ">"); } if (sa_p->ips_auth_bits) seq_printf(seq, " alen=%d", sa_p->ips_auth_bits); if (sa_p->ips_key_bits_a) seq_printf(seq, " aklen=%d", sa_p->ips_key_bits_a); if (sa_p->ips_errs.ips_auth_errs) seq_printf(seq, " auth_errs=%d", sa_p->ips_errs.ips_auth_errs); if (sa_p->ips_key_bits_e) seq_printf(seq, " eklen=%d", sa_p->ips_key_bits_e); if (sa_p->ips_errs.ips_encsize_errs) seq_printf(seq, " encr_size_errs=%d", sa_p->ips_errs.ips_encsize_errs); if (sa_p->ips_errs.ips_encpad_errs) seq_printf(seq, " encr_pad_errs=%d", sa_p->ips_errs.ips_encpad_errs); seq_printf(seq, " jiffies=%lu", jiffies); seq_printf(seq, " life(c,s,h)="); ipsec_lifetime_format(seq, "alloc", ipsec_life_countbased, &sa_p->ips_life.ipl_allocations); ipsec_lifetime_format(seq, "bytes", ipsec_life_countbased, &sa_p->ips_life.ipl_bytes); ipsec_lifetime_format(seq, "addtime", ipsec_life_timebased, &sa_p->ips_life.ipl_addtime); ipsec_lifetime_format(seq, "usetime", ipsec_life_timebased, &sa_p->ips_life.ipl_usetime); ipsec_lifetime_format(seq, "packets", ipsec_life_countbased, &sa_p->ips_life.ipl_packets); if (sa_p->ips_life.ipl_usetime.ipl_last) { /* XXX-MCR should be last? */ seq_printf(seq, " idle=%Ld", ipsec_jiffieshz_elapsed(jiffies/HZ, sa_p->ips_life.ipl_usetime.ipl_last)); } #ifdef CONFIG_KLIPS_IPCOMP if (sa_p->ips_said.proto == IPPROTO_COMP && (sa_p->ips_comp_ratio_dbytes || sa_p->ips_comp_ratio_cbytes)) { seq_printf(seq, " ratio=%Ld:%Ld", sa_p->ips_comp_ratio_dbytes, sa_p->ips_comp_ratio_cbytes); } #endif /* CONFIG_KLIPS_IPCOMP */ seq_printf(seq, " natencap="); switch (sa_p->ips_natt_type) { case 0: seq_printf(seq, "none"); break; case ESPINUDP_WITH_NON_IKE: seq_printf(seq, "nonike"); break; case ESPINUDP_WITH_NON_ESP: seq_printf(seq, "nonesp"); break; default: seq_printf(seq, "unknown"); break; } seq_printf(seq, " natsport=%d", sa_p->ips_natt_sport); seq_printf(seq, " natdport=%d", sa_p->ips_natt_dport); /* we decrement by one, because this SA has been referenced in order to dump this info */ seq_printf(seq, " refcount=%d", atomic_read(&sa_p->ips_refcount)-1); #ifdef IPSEC_SA_RECOUNT_DEBUG { int f; seq_printf(seq, "["); for (f = 0; f < sizeof(sa_p->ips_track); f++) seq_printf(seq, "%s%d", f == 0 ? "" : ",", sa_p->ips_track[f]); seq_printf(seq, "]"); } #endif seq_printf(seq, " ref=%d", sa_p->ips_ref); seq_printf(seq, " refhim=%d", sa_p->ips_refhim); if (sa_p->ips_out) { seq_printf(seq, " outif=%s:%d", sa_p->ips_out->name, sa_p->ips_transport_direct); } if (debug_xform) { seq_printf(seq, " reftable=%lu refentry=%lu", (unsigned long)IPsecSAref2table(sa_p->ips_ref), (unsigned long)IPsecSAref2entry(sa_p->ips_ref)); } seq_printf(seq, "\n"); ipsec_sa_put(sa_p, IPSEC_REFPROC); return 0; }