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 2004 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 114 /* ESP-specific drop statistics. */ 115 116 kstat_named_init(&ipdrops_esp_nomem, "esp_nomem", KSTAT_DATA_UINT64); 117 kstat_named_init(&ipdrops_esp_no_sa, "esp_no_sa", KSTAT_DATA_UINT64); 118 kstat_named_init(&ipdrops_esp_early_replay, "esp_early_replay", 119 KSTAT_DATA_UINT64); 120 kstat_named_init(&ipdrops_esp_replay, "esp_replay", KSTAT_DATA_UINT64); 121 kstat_named_init(&ipdrops_esp_bytes_expire, "esp_bytes_expire", 122 KSTAT_DATA_UINT64); 123 kstat_named_init(&ipdrops_esp_bad_padlen, "esp_bad_padlen", 124 KSTAT_DATA_UINT64); 125 kstat_named_init(&ipdrops_esp_bad_padding, "esp_bad_padding", 126 KSTAT_DATA_UINT64); 127 kstat_named_init(&ipdrops_esp_bad_auth, "esp_bad_auth", 128 KSTAT_DATA_UINT64); 129 kstat_named_init(&ipdrops_esp_crypto_failed, "esp_crypto_failed", 130 KSTAT_DATA_UINT64); 131 kstat_named_init(&ipdrops_esp_icmp, "esp_icmp", KSTAT_DATA_UINT64); 132 133 /* AH-specific drop statistics. */ 134 kstat_named_init(&ipdrops_ah_nomem, "ah_nomem", KSTAT_DATA_UINT64); 135 kstat_named_init(&ipdrops_ah_bad_v6_hdrs, "ah_bad_v6_hdrs", 136 KSTAT_DATA_UINT64); 137 kstat_named_init(&ipdrops_ah_bad_v4_opts, "ah_bad_v4_opts", 138 KSTAT_DATA_UINT64); 139 kstat_named_init(&ipdrops_ah_no_sa, "ah_no_sa", KSTAT_DATA_UINT64); 140 kstat_named_init(&ipdrops_ah_bad_length, "ah_bad_length", 141 KSTAT_DATA_UINT64); 142 kstat_named_init(&ipdrops_ah_bad_auth, "ah_bad_auth", 143 KSTAT_DATA_UINT64); 144 kstat_named_init(&ipdrops_ah_crypto_failed, "ah_crypto_failed", 145 KSTAT_DATA_UINT64); 146 kstat_named_init(&ipdrops_ah_early_replay, "ah_early_replay", 147 KSTAT_DATA_UINT64); 148 kstat_named_init(&ipdrops_ah_replay, "ah_replay", KSTAT_DATA_UINT64); 149 kstat_named_init(&ipdrops_ah_bytes_expire, "ah_bytes_expire", 150 KSTAT_DATA_UINT64); 151 152 /* IP-specific drop statistics. */ 153 kstat_named_init(&ipdrops_ip_ipsec_not_loaded, "ip_ipsec_not_loaded", 154 KSTAT_DATA_UINT64); 155 156 kstat_install(ip_drop_kstat); 157 } 158 159 void 160 ip_drop_destroy(void) 161 { 162 kstat_delete(ip_drop_kstat); 163 } 164 165 /* 166 * Register a packet dropper. 167 */ 168 void 169 ip_drop_register(ipdropper_t *ipd, char *name) 170 { 171 if (ipd->ipd_name != NULL) { 172 cmn_err(CE_WARN, 173 "ip_drop_register: ipdropper %s already registered with %s", 174 name, ipd->ipd_name); 175 return; 176 } 177 178 /* Assume that name is reasonable in length. This isn't user-land. */ 179 ipd->ipd_name = kmem_alloc(strlen(name) + 1, KM_SLEEP); 180 (void) strcpy(ipd->ipd_name, name); 181 } 182 183 /* 184 * Un-register a packet dropper. 185 */ 186 void 187 ip_drop_unregister(ipdropper_t *ipd) 188 { 189 kmem_free(ipd->ipd_name, strlen(ipd->ipd_name) + 1); 190 191 ipd->ipd_name = NULL; 192 } 193 194 /* 195 * Actually drop a packet. Many things could happen here, but at the least, 196 * the packet will be freemsg()ed. 197 */ 198 /* ARGSUSED */ 199 void 200 ip_drop_packet(mblk_t *mp, boolean_t inbound, ill_t *arriving, 201 ire_t *outbound_ire, struct kstat_named *counter, ipdropper_t *who_called) 202 { 203 mblk_t *ipsec_mp = NULL; 204 ipsec_in_t *ii = NULL; 205 ipsec_out_t *io = NULL; 206 ipsec_info_t *in; 207 uint8_t vers; 208 209 if (mp == NULL) { 210 /* 211 * Return immediately - NULL packets should not affect any 212 * statistics. 213 */ 214 return; 215 } 216 217 if (DB_TYPE(mp) == M_CTL) { 218 in = (ipsec_info_t *)mp->b_rptr; 219 220 if (in->ipsec_info_type == IPSEC_IN) 221 ii = (ipsec_in_t *)in; 222 else if (in->ipsec_info_type == IPSEC_OUT) 223 io = (ipsec_out_t *)in; 224 225 /* See if this is an ICMP packet (check for v4/v6). */ 226 vers = (*mp->b_rptr) >> 4; 227 if (vers != IPV4_VERSION && vers != IPV6_VERSION) { 228 /* 229 * If not, it's some other sort of M_CTL to be freed. 230 * For now, treat it like an ordinary packet. 231 */ 232 ipsec_mp = mp; 233 mp = mp->b_cont; 234 } 235 } 236 237 /* Reality checks */ 238 if (inbound && io != NULL) 239 cmn_err(CE_WARN, 240 "ip_drop_packet: inbound packet with IPSEC_OUT"); 241 242 if (outbound_ire != NULL && ii != NULL) 243 cmn_err(CE_WARN, 244 "ip_drop_packet: outbound packet with IPSEC_IN"); 245 246 /* At this point, mp always points to the data. */ 247 /* 248 * Can't make the assertion yet - It could be an inbound ICMP 249 * message, which is M_CTL but with data in it. 250 */ 251 /* ASSERT(mp->b_datap->db_type == M_DATA); */ 252 253 /* Increment the bean counter, if available. */ 254 if (counter != NULL) { 255 switch (counter->data_type) { 256 case KSTAT_DATA_INT32: 257 counter->value.i32++; 258 break; 259 case KSTAT_DATA_UINT32: 260 counter->value.ui32++; 261 break; 262 case KSTAT_DATA_INT64: 263 counter->value.i64++; 264 break; 265 case KSTAT_DATA_UINT64: 266 counter->value.ui64++; 267 break; 268 /* Other types we can't handle for now. */ 269 } 270 271 /* TODO? Copy out kstat name for use in logging. */ 272 } 273 274 /* TODO: log the packet details if logging is called for. */ 275 /* TODO: queue the packet onto a snoop-friendly queue. */ 276 277 /* If I haven't queued the packet or some such nonsense, free it. */ 278 if (ipsec_mp != NULL) 279 freeb(ipsec_mp); 280 freemsg(mp); 281 } 282