1 /*- 2 * Copyright (c) 2015 Yandex LLC 3 * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org> 4 * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #ifndef _IP_FW_NAT64LSN_H_ 32 #define _IP_FW_NAT64LSN_H_ 33 34 #define NAT64_CHUNK_SIZE_BITS 6 /* 64 ports */ 35 #define NAT64_CHUNK_SIZE (1 << NAT64_CHUNK_SIZE_BITS) 36 37 #define NAT64_MIN_PORT 1024 38 #define NAT64_MIN_CHUNK (NAT64_MIN_PORT >> NAT64_CHUNK_SIZE_BITS) 39 40 struct st_ptr { 41 uint8_t idx; /* index in nh->pg_ptr array. 42 * NOTE: it starts from 1. 43 */ 44 uint8_t off; 45 }; 46 #define NAT64LSN_MAXPGPTR ((1 << (sizeof(uint8_t) * NBBY)) - 1) 47 #define NAT64LSN_PGPTRMASKBITS (sizeof(uint64_t) * NBBY) 48 #define NAT64LSN_PGPTRNMASK (roundup(NAT64LSN_MAXPGPTR, \ 49 NAT64LSN_PGPTRMASKBITS) / NAT64LSN_PGPTRMASKBITS) 50 51 struct nat64lsn_portgroup; 52 /* sizeof(struct nat64lsn_host) = 64 + 64x2 + 8x8 = 256 bytes */ 53 struct nat64lsn_host { 54 struct rwlock h_lock; /* Host states lock */ 55 56 struct in6_addr addr; 57 struct nat64lsn_host *next; 58 uint16_t timestamp; /* Last altered */ 59 uint16_t hsize; /* ports hash size */ 60 uint16_t pg_used; /* Number of portgroups used */ 61 #define NAT64LSN_REMAININGPG 8 /* Number of remaining PG before 62 * requesting of new chunk of indexes. 63 */ 64 uint16_t pg_allocated; /* Number of portgroups indexes 65 * allocated. 66 */ 67 #define NAT64LSN_HSIZE 64 68 struct st_ptr phash[NAT64LSN_HSIZE]; /* XXX: hardcoded size */ 69 /* 70 * PG indexes are stored in chunks with 32 elements. 71 * The maximum count is limited to 255 due to st_ptr->idx is uint8_t. 72 */ 73 #define NAT64LSN_PGIDX_CHUNK 32 74 #define NAT64LSN_PGNIDX (roundup(NAT64LSN_MAXPGPTR, \ 75 NAT64LSN_PGIDX_CHUNK) / NAT64LSN_PGIDX_CHUNK) 76 struct nat64lsn_portgroup **pg_ptr[NAT64LSN_PGNIDX]; /* PG indexes */ 77 }; 78 79 #define NAT64_RLOCK_ASSERT(h) rw_assert(&(h)->h_lock, RA_RLOCKED) 80 #define NAT64_WLOCK_ASSERT(h) rw_assert(&(h)->h_lock, RA_WLOCKED) 81 82 #define NAT64_RLOCK(h) rw_rlock(&(h)->h_lock) 83 #define NAT64_RUNLOCK(h) rw_runlock(&(h)->h_lock) 84 #define NAT64_WLOCK(h) rw_wlock(&(h)->h_lock) 85 #define NAT64_WUNLOCK(h) rw_wunlock(&(h)->h_lock) 86 #define NAT64_LOCK(h) NAT64_WLOCK(h) 87 #define NAT64_UNLOCK(h) NAT64_WUNLOCK(h) 88 #define NAT64_LOCK_INIT(h) do { \ 89 rw_init(&(h)->h_lock, "NAT64 host lock"); \ 90 } while (0) 91 92 #define NAT64_LOCK_DESTROY(h) do { \ 93 rw_destroy(&(h)->h_lock); \ 94 } while (0) 95 96 /* Internal proto index */ 97 #define NAT_PROTO_TCP 1 98 #define NAT_PROTO_UDP 2 99 #define NAT_PROTO_ICMP 3 100 101 #define NAT_MAX_PROTO 4 102 extern uint8_t nat64lsn_rproto_map[NAT_MAX_PROTO]; 103 104 VNET_DECLARE(uint16_t, nat64lsn_eid); 105 #define V_nat64lsn_eid VNET(nat64lsn_eid) 106 #define IPFW_TLV_NAT64LSN_NAME IPFW_TLV_EACTION_NAME(V_nat64lsn_eid) 107 108 /* Timestamp macro */ 109 #define _CT ((int)time_uptime % 65536) 110 #define SET_AGE(x) (x) = _CT 111 #define GET_AGE(x) ((_CT >= (x)) ? _CT - (x) : \ 112 (int)65536 + _CT - (x)) 113 114 #ifdef __LP64__ 115 /* ffsl() is capable of checking 64-bit ints */ 116 #define _FFS64 117 #endif 118 119 /* 16 bytes */ 120 struct nat64lsn_state { 121 union { 122 struct { 123 in_addr_t faddr; /* Remote IPv4 address */ 124 uint16_t fport; /* Remote IPv4 port */ 125 uint16_t lport; /* Local IPv6 port */ 126 }s; 127 uint64_t hkey; 128 } u; 129 uint8_t nat_proto; 130 uint8_t flags; 131 uint16_t timestamp; 132 struct st_ptr cur; /* Index of portgroup in nat64lsn_host */ 133 struct st_ptr next; /* Next entry index */ 134 }; 135 136 /* 137 * 1024+32 bytes per 64 states, used to store state 138 * AND for outside-in state lookup 139 */ 140 struct nat64lsn_portgroup { 141 struct nat64lsn_host *host; /* IPv6 source host info */ 142 in_addr_t aaddr; /* Alias addr, network format */ 143 uint16_t aport; /* Base port */ 144 uint16_t timestamp; 145 uint8_t nat_proto; 146 uint8_t spare[3]; 147 uint32_t idx; 148 #ifdef _FFS64 149 uint64_t freemask; /* Mask of free entries */ 150 #else 151 uint32_t freemask[2]; /* Mask of free entries */ 152 #endif 153 struct nat64lsn_state states[NAT64_CHUNK_SIZE]; /* State storage */ 154 }; 155 #ifdef _FFS64 156 #define PG_MARK_BUSY_IDX(_pg, _idx) (_pg)->freemask &= ~((uint64_t)1<<(_idx)) 157 #define PG_MARK_FREE_IDX(_pg, _idx) (_pg)->freemask |= ((uint64_t)1<<(_idx)) 158 #define PG_IS_FREE_IDX(_pg, _idx) ((_pg)->freemask & ((uint64_t)1<<(_idx))) 159 #define PG_IS_BUSY_IDX(_pg, _idx) (PG_IS_FREE_IDX(_pg, _idx) == 0) 160 #define PG_GET_FREE_IDX(_pg) (ffsll((_pg)->freemask)) 161 #define PG_IS_EMPTY(_pg) (((_pg)->freemask + 1) == 0) 162 #else 163 #define PG_MARK_BUSY_IDX(_pg, _idx) \ 164 (_pg)->freemask[(_idx) / 32] &= ~((u_long)1<<((_idx) % 32)) 165 #define PG_MARK_FREE_IDX(_pg, _idx) \ 166 (_pg)->freemask[(_idx) / 32] |= ((u_long)1<<((_idx) % 32)) 167 #define PG_IS_FREE_IDX(_pg, _idx) \ 168 ((_pg)->freemask[(_idx) / 32] & ((u_long)1<<((_idx) % 32))) 169 #define PG_IS_BUSY_IDX(_pg, _idx) (PG_IS_FREE_IDX(_pg, _idx) == 0) 170 #define PG_GET_FREE_IDX(_pg) _pg_get_free_idx(_pg) 171 #define PG_IS_EMPTY(_pg) \ 172 ((((_pg)->freemask[0] + 1) == 0 && ((_pg)->freemask[1] + 1) == 0)) 173 174 static inline int 175 _pg_get_free_idx(const struct nat64lsn_portgroup *pg) 176 { 177 int i; 178 179 if ((i = ffsl(pg->freemask[0])) != 0) 180 return (i); 181 if ((i = ffsl(pg->freemask[1])) != 0) 182 return (i + 32); 183 return (0); 184 } 185 186 #endif 187 188 TAILQ_HEAD(nat64lsn_job_head, nat64lsn_job_item); 189 190 #define NAT64LSN_FLAGSMASK (NAT64_LOG) 191 struct nat64lsn_cfg { 192 struct named_object no; 193 //struct nat64_exthost *ex; /* Pointer to external addr array */ 194 struct nat64lsn_portgroup **pg; /* XXX: array of pointers */ 195 struct nat64lsn_host **ih; /* Host hash */ 196 uint32_t prefix4; /* IPv4 prefix */ 197 uint32_t pmask4; /* IPv4 prefix mask */ 198 uint32_t ihsize; /* IPv6 host hash size */ 199 uint8_t plen4; 200 uint8_t plen6; 201 uint8_t nomatch_verdict;/* What to return to ipfw on no-match */ 202 uint8_t nomatch_final; /* Exit outer loop? */ 203 struct in6_addr prefix6; /* IPv6 prefix to embed IPv4 hosts */ 204 205 uint32_t ihcount; /* Number of items in host hash */ 206 int max_chunks; /* Max chunks per client */ 207 int agg_prefix_len; /* Prefix length to count */ 208 int agg_prefix_max; /* Max hosts per agg prefix */ 209 uint32_t jmaxlen; /* Max jobqueue length */ 210 uint32_t flags; 211 uint16_t min_chunk; /* Min port group # to use */ 212 uint16_t max_chunk; /* Max port group # to use */ 213 uint16_t nh_delete_delay; /* Stale host delete delay */ 214 uint16_t pg_delete_delay; /* Stale portgroup del delay */ 215 uint16_t st_syn_ttl; /* TCP syn expire */ 216 uint16_t st_close_ttl; /* TCP fin expire */ 217 uint16_t st_estab_ttl; /* TCP established expire */ 218 uint16_t st_udp_ttl; /* UDP expire */ 219 uint16_t st_icmp_ttl; /* ICMP expire */ 220 uint32_t protochunks[NAT_MAX_PROTO];/* Number of chunks used */ 221 222 struct callout periodic; 223 struct callout jcallout; 224 struct ip_fw_chain *ch; 225 struct vnet *vp; 226 struct nat64lsn_job_head jhead; 227 int jlen; 228 char name[64]; /* Nat instance name */ 229 nat64_stats_block stats; 230 }; 231 232 struct nat64lsn_cfg *nat64lsn_init_instance(struct ip_fw_chain *ch, 233 size_t numaddr); 234 void nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg); 235 void nat64lsn_start_instance(struct nat64lsn_cfg *cfg); 236 void nat64lsn_init_internal(void); 237 void nat64lsn_uninit_internal(void); 238 int ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args, 239 ipfw_insn *cmd, int *done); 240 241 void 242 nat64lsn_dump_state(const struct nat64lsn_cfg *cfg, 243 const struct nat64lsn_portgroup *pg, const struct nat64lsn_state *st, 244 const char *px, int off); 245 /* 246 * Portgroup layout 247 * addr x nat_proto x port_off 248 * 249 */ 250 251 #define _ADDR_PG_PROTO_COUNT (65536 >> NAT64_CHUNK_SIZE_BITS) 252 #define _ADDR_PG_COUNT (_ADDR_PG_PROTO_COUNT * NAT_MAX_PROTO) 253 254 #define GET_ADDR_IDX(_cfg, _addr) ((_addr) - ((_cfg)->prefix4)) 255 #define __GET_PORTGROUP_IDX(_proto, _port) \ 256 ((_proto - 1) * _ADDR_PG_PROTO_COUNT + \ 257 ((_port) >> NAT64_CHUNK_SIZE_BITS)) 258 259 #define _GET_PORTGROUP_IDX(_cfg, _addr, _proto, _port) \ 260 GET_ADDR_IDX(_cfg, _addr) * _ADDR_PG_COUNT + \ 261 __GET_PORTGROUP_IDX(_proto, _port) 262 #define GET_PORTGROUP(_cfg, _addr, _proto, _port) \ 263 ((_cfg)->pg[_GET_PORTGROUP_IDX(_cfg, _addr, _proto, _port)]) 264 265 #define PORTGROUP_CHUNK(_nh, _idx) \ 266 ((_nh)->pg_ptr[(_idx)]) 267 #define PORTGROUP_BYSIDX(_cfg, _nh, _idx) \ 268 (PORTGROUP_CHUNK(_nh, (_idx - 1) / NAT64LSN_PGIDX_CHUNK) \ 269 [((_idx) - 1) % NAT64LSN_PGIDX_CHUNK]) 270 271 272 /* Chained hash table */ 273 #define CHT_FIND(_ph, _hsize, _PX, _x, _key) do { \ 274 unsigned int _buck = _PX##hash(_key) & (_hsize - 1); \ 275 _PX##lock(_ph, _buck); \ 276 _x = _PX##first(_ph, _buck); \ 277 for ( ; _x != NULL; _x = _PX##next(_x)) { \ 278 if (_PX##cmp(_key, _PX##val(_x))) \ 279 break; \ 280 } \ 281 if (_x == NULL) \ 282 _PX##unlock(_ph, _buck); \ 283 } while(0) 284 285 #define CHT_UNLOCK_BUCK(_ph, _PX, _buck) \ 286 _PX##unlock(_ph, _buck); 287 288 #define CHT_UNLOCK_KEY(_ph, _hsize, _PX, _key) do { \ 289 unsigned int _buck = _PX##hash(_key) & (_hsize - 1); \ 290 _PX##unlock(_ph, _buck); \ 291 } while(0) 292 293 #define CHT_INSERT_HEAD(_ph, _hsize, _PX, _i) do { \ 294 unsigned int _buck = _PX##hash(_PX##val(_i)) & (_hsize - 1); \ 295 _PX##lock(_ph, _buck); \ 296 _PX##next(_i) = _PX##first(_ph, _buck); \ 297 _PX##first(_ph, _buck) = _i; \ 298 _PX##unlock(_ph, _buck); \ 299 } while(0) 300 301 #define CHT_REMOVE(_ph, _hsize, _PX, _x, _tmp, _key) do { \ 302 unsigned int _buck = _PX##hash(_key) & (_hsize - 1); \ 303 _PX##lock(_ph, _buck); \ 304 _x = _PX##first(_ph, _buck); \ 305 _tmp = NULL; \ 306 for ( ; _x != NULL; _tmp = _x, _x = _PX##next(_x)) { \ 307 if (_PX##cmp(_key, _PX##val(_x))) \ 308 break; \ 309 } \ 310 if (_x != NULL) { \ 311 if (_tmp == NULL) \ 312 _PX##first(_ph, _buck) = _PX##next(_x); \ 313 else \ 314 _PX##next(_tmp) = _PX##next(_x); \ 315 } \ 316 _PX##unlock(_ph, _buck); \ 317 } while(0) 318 319 #define CHT_FOREACH_SAFE(_ph, _hsize, _PX, _x, _tmp, _cb, _arg) do { \ 320 for (unsigned int _i = 0; _i < _hsize; _i++) { \ 321 _PX##lock(_ph, _i); \ 322 _x = _PX##first(_ph, _i); \ 323 _tmp = NULL; \ 324 for (; _x != NULL; _tmp = _x, _x = _PX##next(_x)) { \ 325 if (_cb(_x, _arg) == 0) \ 326 continue; \ 327 if (_tmp == NULL) \ 328 _PX##first(_ph, _i) = _PX##next(_x); \ 329 else \ 330 _tmp = _PX##next(_x); \ 331 } \ 332 _PX##unlock(_ph, _i); \ 333 } \ 334 } while(0) 335 336 #define CHT_RESIZE(_ph, _hsize, _nph, _nhsize, _PX, _x, _y) do { \ 337 unsigned int _buck; \ 338 for (unsigned int _i = 0; _i < _hsize; _i++) { \ 339 _x = _PX##first(_ph, _i); \ 340 _y = _x; \ 341 while (_y != NULL) { \ 342 _buck = _PX##hash(_PX##val(_x)) & (_nhsize - 1);\ 343 _y = _PX##next(_x); \ 344 _PX##next(_x) = _PX##first(_nph, _buck); \ 345 _PX##first(_nph, _buck) = _x; \ 346 } \ 347 } \ 348 } while(0) 349 350 #endif /* _IP_FW_NAT64LSN_H_ */ 351 352