1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/stream.h> 31 #include <sys/strsun.h> 32 #include <sys/sunddi.h> 33 #include <sys/kstat.h> 34 #include <sys/kmem.h> 35 #include <net/pfkeyv2.h> 36 #include <inet/common.h> 37 #include <inet/ip.h> 38 #include <inet/ip6.h> 39 #include <inet/ipsec_info.h> 40 #include <inet/ipdrop.h> 41 42 /* 43 * Packet drop facility. 44 */ 45 46 kstat_t *ip_drop_kstat; 47 struct ip_dropstats *ip_drop_types; 48 49 /* 50 * Initialize drop facility kstats. 51 */ 52 void 53 ip_drop_init(void) 54 { 55 ip_drop_kstat = kstat_create("ip", 0, "ipdrop", "net", 56 KSTAT_TYPE_NAMED, sizeof (*ip_drop_types) / sizeof (kstat_named_t), 57 KSTAT_FLAG_PERSISTENT); 58 59 if (ip_drop_kstat == NULL) 60 return; 61 62 ip_drop_types = ip_drop_kstat->ks_data; 63 64 /* TCP IPsec drop statistics. */ 65 kstat_named_init(&ipdrops_tcp_clear, "tcp_clear", KSTAT_DATA_UINT64); 66 kstat_named_init(&ipdrops_tcp_secure, "tcp_secure", KSTAT_DATA_UINT64); 67 kstat_named_init(&ipdrops_tcp_mismatch, "tcp_mismatch", 68 KSTAT_DATA_UINT64); 69 kstat_named_init(&ipdrops_tcp_ipsec_alloc, "tcp_ipsec_alloc", 70 KSTAT_DATA_UINT64); 71 72 /* SADB-specific drop statistics. */ 73 kstat_named_init(&ipdrops_sadb_inlarval_timeout, 74 "sadb_inlarval_timeout", KSTAT_DATA_UINT64); 75 kstat_named_init(&ipdrops_sadb_inlarval_replace, 76 "sadb_inlarval_replace", KSTAT_DATA_UINT64); 77 kstat_named_init(&ipdrops_sadb_acquire_nomem, 78 "sadb_acquire_nomem", KSTAT_DATA_UINT64); 79 kstat_named_init(&ipdrops_sadb_acquire_toofull, 80 "sadb_acquire_toofull", KSTAT_DATA_UINT64); 81 kstat_named_init(&ipdrops_sadb_acquire_timeout, 82 "sadb_acquire_timeout", KSTAT_DATA_UINT64); 83 84 /* SPD drop statistics. */ 85 kstat_named_init(&ipdrops_spd_ahesp_diffid, "spd_ahesp_diffid", 86 KSTAT_DATA_UINT64); 87 kstat_named_init(&ipdrops_spd_loopback_mismatch, 88 "spd_loopback_mismatch", KSTAT_DATA_UINT64); 89 kstat_named_init(&ipdrops_spd_explicit, "spd_explicit", 90 KSTAT_DATA_UINT64); 91 kstat_named_init(&ipdrops_spd_got_secure, "spd_got_secure", 92 KSTAT_DATA_UINT64); 93 kstat_named_init(&ipdrops_spd_got_clear, "spd_got_clear", 94 KSTAT_DATA_UINT64); 95 kstat_named_init(&ipdrops_spd_bad_ahalg, "spd_bad_ahalg", 96 KSTAT_DATA_UINT64); 97 kstat_named_init(&ipdrops_spd_got_ah, "spd_got_ah", KSTAT_DATA_UINT64); 98 kstat_named_init(&ipdrops_spd_bad_espealg, "spd_bad_espealg", 99 KSTAT_DATA_UINT64); 100 kstat_named_init(&ipdrops_spd_bad_espaalg, "spd_bad_espaalg", 101 KSTAT_DATA_UINT64); 102 kstat_named_init(&ipdrops_spd_got_esp, "spd_got_esp", 103 KSTAT_DATA_UINT64); 104 kstat_named_init(&ipdrops_spd_got_selfencap, "spd_got_selfencap", 105 KSTAT_DATA_UINT64); 106 kstat_named_init(&ipdrops_spd_bad_selfencap, "spd_bad_selfencap", 107 KSTAT_DATA_UINT64); 108 kstat_named_init(&ipdrops_spd_nomem, "spd_nomem", KSTAT_DATA_UINT64); 109 kstat_named_init(&ipdrops_spd_ah_badid, "spd_ah_badid", 110 KSTAT_DATA_UINT64); 111 kstat_named_init(&ipdrops_spd_esp_badid, "spd_esp_badid", 112 KSTAT_DATA_UINT64); 113 kstat_named_init(&ipdrops_spd_ah_innermismatch, 114 "spd_ah_innermismatch", KSTAT_DATA_UINT64); 115 kstat_named_init(&ipdrops_spd_esp_innermismatch, 116 "spd_esp_innermismatch", KSTAT_DATA_UINT64); 117 118 /* ESP-specific drop statistics. */ 119 120 kstat_named_init(&ipdrops_esp_nomem, "esp_nomem", KSTAT_DATA_UINT64); 121 kstat_named_init(&ipdrops_esp_no_sa, "esp_no_sa", KSTAT_DATA_UINT64); 122 kstat_named_init(&ipdrops_esp_early_replay, "esp_early_replay", 123 KSTAT_DATA_UINT64); 124 kstat_named_init(&ipdrops_esp_replay, "esp_replay", KSTAT_DATA_UINT64); 125 kstat_named_init(&ipdrops_esp_bytes_expire, "esp_bytes_expire", 126 KSTAT_DATA_UINT64); 127 kstat_named_init(&ipdrops_esp_bad_padlen, "esp_bad_padlen", 128 KSTAT_DATA_UINT64); 129 kstat_named_init(&ipdrops_esp_bad_padding, "esp_bad_padding", 130 KSTAT_DATA_UINT64); 131 kstat_named_init(&ipdrops_esp_bad_auth, "esp_bad_auth", 132 KSTAT_DATA_UINT64); 133 kstat_named_init(&ipdrops_esp_crypto_failed, "esp_crypto_failed", 134 KSTAT_DATA_UINT64); 135 kstat_named_init(&ipdrops_esp_icmp, "esp_icmp", KSTAT_DATA_UINT64); 136 137 /* AH-specific drop statistics. */ 138 kstat_named_init(&ipdrops_ah_nomem, "ah_nomem", KSTAT_DATA_UINT64); 139 kstat_named_init(&ipdrops_ah_bad_v6_hdrs, "ah_bad_v6_hdrs", 140 KSTAT_DATA_UINT64); 141 kstat_named_init(&ipdrops_ah_bad_v4_opts, "ah_bad_v4_opts", 142 KSTAT_DATA_UINT64); 143 kstat_named_init(&ipdrops_ah_no_sa, "ah_no_sa", KSTAT_DATA_UINT64); 144 kstat_named_init(&ipdrops_ah_bad_length, "ah_bad_length", 145 KSTAT_DATA_UINT64); 146 kstat_named_init(&ipdrops_ah_bad_auth, "ah_bad_auth", 147 KSTAT_DATA_UINT64); 148 kstat_named_init(&ipdrops_ah_crypto_failed, "ah_crypto_failed", 149 KSTAT_DATA_UINT64); 150 kstat_named_init(&ipdrops_ah_early_replay, "ah_early_replay", 151 KSTAT_DATA_UINT64); 152 kstat_named_init(&ipdrops_ah_replay, "ah_replay", KSTAT_DATA_UINT64); 153 kstat_named_init(&ipdrops_ah_bytes_expire, "ah_bytes_expire", 154 KSTAT_DATA_UINT64); 155 156 /* IP-specific drop statistics. */ 157 kstat_named_init(&ipdrops_ip_ipsec_not_loaded, "ip_ipsec_not_loaded", 158 KSTAT_DATA_UINT64); 159 160 kstat_install(ip_drop_kstat); 161 } 162 163 void 164 ip_drop_destroy(void) 165 { 166 kstat_delete(ip_drop_kstat); 167 } 168 169 /* 170 * Register a packet dropper. 171 */ 172 void 173 ip_drop_register(ipdropper_t *ipd, char *name) 174 { 175 if (ipd->ipd_name != NULL) { 176 cmn_err(CE_WARN, 177 "ip_drop_register: ipdropper %s already registered with %s", 178 name, ipd->ipd_name); 179 return; 180 } 181 182 /* Assume that name is reasonable in length. This isn't user-land. */ 183 ipd->ipd_name = kmem_alloc(strlen(name) + 1, KM_SLEEP); 184 (void) strcpy(ipd->ipd_name, name); 185 } 186 187 /* 188 * Un-register a packet dropper. 189 */ 190 void 191 ip_drop_unregister(ipdropper_t *ipd) 192 { 193 kmem_free(ipd->ipd_name, strlen(ipd->ipd_name) + 1); 194 195 ipd->ipd_name = NULL; 196 } 197 198 /* 199 * Actually drop a packet. Many things could happen here, but at the least, 200 * the packet will be freemsg()ed. 201 */ 202 /* ARGSUSED */ 203 void 204 ip_drop_packet(mblk_t *mp, boolean_t inbound, ill_t *arriving, 205 ire_t *outbound_ire, struct kstat_named *counter, ipdropper_t *who_called) 206 { 207 mblk_t *ipsec_mp = NULL; 208 ipsec_in_t *ii = NULL; 209 ipsec_out_t *io = NULL; 210 ipsec_info_t *in; 211 uint8_t vers; 212 213 if (mp == NULL) { 214 /* 215 * Return immediately - NULL packets should not affect any 216 * statistics. 217 */ 218 return; 219 } 220 221 if (DB_TYPE(mp) == M_CTL) { 222 in = (ipsec_info_t *)mp->b_rptr; 223 224 if (in->ipsec_info_type == IPSEC_IN) 225 ii = (ipsec_in_t *)in; 226 else if (in->ipsec_info_type == IPSEC_OUT) 227 io = (ipsec_out_t *)in; 228 229 /* See if this is an ICMP packet (check for v4/v6). */ 230 vers = (*mp->b_rptr) >> 4; 231 if (vers != IPV4_VERSION && vers != IPV6_VERSION) { 232 /* 233 * If not, it's some other sort of M_CTL to be freed. 234 * For now, treat it like an ordinary packet. 235 */ 236 ipsec_mp = mp; 237 mp = mp->b_cont; 238 } 239 } 240 241 /* Reality checks */ 242 if (inbound && io != NULL) 243 cmn_err(CE_WARN, 244 "ip_drop_packet: inbound packet with IPSEC_OUT"); 245 246 if (outbound_ire != NULL && ii != NULL) 247 cmn_err(CE_WARN, 248 "ip_drop_packet: outbound packet with IPSEC_IN"); 249 250 /* At this point, mp always points to the data. */ 251 /* 252 * Can't make the assertion yet - It could be an inbound ICMP 253 * message, which is M_CTL but with data in it. 254 */ 255 /* ASSERT(mp->b_datap->db_type == M_DATA); */ 256 257 /* Increment the bean counter, if available. */ 258 if (counter != NULL) { 259 switch (counter->data_type) { 260 case KSTAT_DATA_INT32: 261 counter->value.i32++; 262 break; 263 case KSTAT_DATA_UINT32: 264 counter->value.ui32++; 265 break; 266 case KSTAT_DATA_INT64: 267 counter->value.i64++; 268 break; 269 case KSTAT_DATA_UINT64: 270 counter->value.ui64++; 271 break; 272 /* Other types we can't handle for now. */ 273 } 274 275 /* TODO? Copy out kstat name for use in logging. */ 276 } 277 278 /* TODO: log the packet details if logging is called for. */ 279 /* TODO: queue the packet onto a snoop-friendly queue. */ 280 281 /* If I haven't queued the packet or some such nonsense, free it. */ 282 if (ipsec_mp != NULL) 283 freeb(ipsec_mp); 284 freemsg(mp); 285 } 286