1d8caf56eSAndrey V. Elsukov /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3002cae78SAndrey V. Elsukov * 4*4a77657cSAndrey V. Elsukov * Copyright (c) 2015-2020 Yandex LLC 5d8caf56eSAndrey V. Elsukov * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org> 6*4a77657cSAndrey V. Elsukov * Copyright (c) 2015-2020 Andrey V. Elsukov <ae@FreeBSD.org> 7d8caf56eSAndrey V. Elsukov * 8d8caf56eSAndrey V. Elsukov * Redistribution and use in source and binary forms, with or without 9d8caf56eSAndrey V. Elsukov * modification, are permitted provided that the following conditions 10d8caf56eSAndrey V. Elsukov * are met: 11d8caf56eSAndrey V. Elsukov * 12d8caf56eSAndrey V. Elsukov * 1. Redistributions of source code must retain the above copyright 13d8caf56eSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer. 14d8caf56eSAndrey V. Elsukov * 2. Redistributions in binary form must reproduce the above copyright 15d8caf56eSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer in the 16d8caf56eSAndrey V. Elsukov * documentation and/or other materials provided with the distribution. 17d8caf56eSAndrey V. Elsukov * 18d8caf56eSAndrey V. Elsukov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19d8caf56eSAndrey V. Elsukov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20d8caf56eSAndrey V. Elsukov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21d8caf56eSAndrey V. Elsukov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22d8caf56eSAndrey V. Elsukov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23d8caf56eSAndrey V. Elsukov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24d8caf56eSAndrey V. Elsukov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25d8caf56eSAndrey V. Elsukov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26d8caf56eSAndrey V. Elsukov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27d8caf56eSAndrey V. Elsukov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28d8caf56eSAndrey V. Elsukov */ 29d8caf56eSAndrey V. Elsukov 30d8caf56eSAndrey V. Elsukov #ifndef _IP_FW_NAT64LSN_H_ 31d8caf56eSAndrey V. Elsukov #define _IP_FW_NAT64LSN_H_ 32d8caf56eSAndrey V. Elsukov 33782360deSAndrey V. Elsukov #include "ip_fw_nat64.h" 34782360deSAndrey V. Elsukov #include "nat64_translate.h" 35782360deSAndrey V. Elsukov 36d8caf56eSAndrey V. Elsukov #define NAT64_MIN_PORT 1024 37d18c1f26SAndrey V. Elsukov struct nat64lsn_host; 38d18c1f26SAndrey V. Elsukov struct nat64lsn_alias; 39d8caf56eSAndrey V. Elsukov 40d18c1f26SAndrey V. Elsukov struct nat64lsn_state { 41d18c1f26SAndrey V. Elsukov /* IPv6 host entry keeps hash table to speedup state lookup */ 42d18c1f26SAndrey V. Elsukov CK_SLIST_ENTRY(nat64lsn_state) entries; 43d18c1f26SAndrey V. Elsukov struct nat64lsn_host *host; 44d18c1f26SAndrey V. Elsukov 45d18c1f26SAndrey V. Elsukov struct in6_addr ip6_dst; /* Destination IPv6 address */ 46d18c1f26SAndrey V. Elsukov 47d18c1f26SAndrey V. Elsukov in_addr_t ip_src; /* Alias IPv4 address */ 48d18c1f26SAndrey V. Elsukov in_addr_t ip_dst; /* Destination IPv4 address */ 49d18c1f26SAndrey V. Elsukov uint16_t dport; /* Destination port */ 50d18c1f26SAndrey V. Elsukov uint16_t sport; /* Source port */ 51d18c1f26SAndrey V. Elsukov 52d18c1f26SAndrey V. Elsukov uint32_t hval; 53d18c1f26SAndrey V. Elsukov uint32_t flags; /* Internal flags */ 54d18c1f26SAndrey V. Elsukov uint16_t aport; 55d18c1f26SAndrey V. Elsukov uint16_t timestamp; /* last used */ 56d18c1f26SAndrey V. Elsukov uint8_t proto; 57d18c1f26SAndrey V. Elsukov uint8_t _spare[7]; 58d8caf56eSAndrey V. Elsukov }; 59d8caf56eSAndrey V. Elsukov 60d18c1f26SAndrey V. Elsukov struct nat64lsn_states_chunk { 61d18c1f26SAndrey V. Elsukov struct nat64lsn_state state[64]; 62d18c1f26SAndrey V. Elsukov }; 63d18c1f26SAndrey V. Elsukov 64d18c1f26SAndrey V. Elsukov #define ISSET64(mask, bit) ((mask) & ((uint64_t)1 << (bit))) 65d18c1f26SAndrey V. Elsukov #define ISSET32(mask, bit) ((mask) & ((uint32_t)1 << (bit))) 66d18c1f26SAndrey V. Elsukov struct nat64lsn_pg { 67d18c1f26SAndrey V. Elsukov uint16_t base_port; 68d18c1f26SAndrey V. Elsukov uint16_t timestamp; 69d18c1f26SAndrey V. Elsukov uint8_t proto; 70d18c1f26SAndrey V. Elsukov uint8_t chunks_count; 71*4a77657cSAndrey V. Elsukov uint16_t flags; 72*4a77657cSAndrey V. Elsukov #define NAT64LSN_DEADPG 1 73d18c1f26SAndrey V. Elsukov 74d18c1f26SAndrey V. Elsukov union { 75d18c1f26SAndrey V. Elsukov uint64_t freemask64; 76d18c1f26SAndrey V. Elsukov uint32_t freemask32[2]; 77d18c1f26SAndrey V. Elsukov uint64_t *freemask64_chunk; 78d18c1f26SAndrey V. Elsukov uint32_t *freemask32_chunk; 79d18c1f26SAndrey V. Elsukov void *freemask_chunk; 80d18c1f26SAndrey V. Elsukov }; 81d18c1f26SAndrey V. Elsukov union { 82d18c1f26SAndrey V. Elsukov struct nat64lsn_states_chunk *states; 83d18c1f26SAndrey V. Elsukov struct nat64lsn_states_chunk **states_chunk; 84d18c1f26SAndrey V. Elsukov }; 85*4a77657cSAndrey V. Elsukov /* 86*4a77657cSAndrey V. Elsukov * An alias object holds chain of all allocated PGs. 87*4a77657cSAndrey V. Elsukov * The chain is used mostly by expiration code. 88*4a77657cSAndrey V. Elsukov */ 89*4a77657cSAndrey V. Elsukov CK_SLIST_ENTRY(nat64lsn_pg) entries; 90d18c1f26SAndrey V. Elsukov }; 91d18c1f26SAndrey V. Elsukov 92d18c1f26SAndrey V. Elsukov #define CHUNK_BY_FADDR(p, a) ((a) & ((p)->chunks_count - 1)) 93d18c1f26SAndrey V. Elsukov 94d18c1f26SAndrey V. Elsukov #ifdef __LP64__ 95d18c1f26SAndrey V. Elsukov #define FREEMASK_CHUNK(p, v) \ 96d18c1f26SAndrey V. Elsukov ((p)->chunks_count == 1 ? &(p)->freemask64 : \ 97d18c1f26SAndrey V. Elsukov &(p)->freemask64_chunk[CHUNK_BY_FADDR(p, v)]) 98d18c1f26SAndrey V. Elsukov #define FREEMASK_BITCOUNT(pg, faddr) \ 99d18c1f26SAndrey V. Elsukov bitcount64(*FREEMASK_CHUNK((pg), (faddr))) 100d18c1f26SAndrey V. Elsukov #else 101d18c1f26SAndrey V. Elsukov #define FREEMASK_CHUNK(p, v) \ 102d18c1f26SAndrey V. Elsukov ((p)->chunks_count == 1 ? &(p)->freemask32[0] : \ 103d18c1f26SAndrey V. Elsukov &(p)->freemask32_chunk[CHUNK_BY_FADDR(p, v) * 2]) 104d18c1f26SAndrey V. Elsukov #define FREEMASK_BITCOUNT(pg, faddr) \ 105d18c1f26SAndrey V. Elsukov bitcount64(*(uint64_t *)FREEMASK_CHUNK((pg), (faddr))) 106d18c1f26SAndrey V. Elsukov #endif /* !__LP64__ */ 107d18c1f26SAndrey V. Elsukov 108d18c1f26SAndrey V. Elsukov struct nat64lsn_pgchunk { 109d18c1f26SAndrey V. Elsukov struct nat64lsn_pg *pgptr[32]; 110d18c1f26SAndrey V. Elsukov }; 111d18c1f26SAndrey V. Elsukov 112d18c1f26SAndrey V. Elsukov struct nat64lsn_aliaslink { 113d18c1f26SAndrey V. Elsukov CK_SLIST_ENTRY(nat64lsn_aliaslink) alias_entries; 114d18c1f26SAndrey V. Elsukov CK_SLIST_ENTRY(nat64lsn_aliaslink) host_entries; 115d18c1f26SAndrey V. Elsukov struct nat64lsn_alias *alias; 116d18c1f26SAndrey V. Elsukov }; 117d18c1f26SAndrey V. Elsukov 118d18c1f26SAndrey V. Elsukov CK_SLIST_HEAD(nat64lsn_aliaslink_slist, nat64lsn_aliaslink); 119d18c1f26SAndrey V. Elsukov CK_SLIST_HEAD(nat64lsn_states_slist, nat64lsn_state); 120d18c1f26SAndrey V. Elsukov CK_SLIST_HEAD(nat64lsn_hosts_slist, nat64lsn_host); 121d18c1f26SAndrey V. Elsukov CK_SLIST_HEAD(nat64lsn_pg_slist, nat64lsn_pg); 122d18c1f26SAndrey V. Elsukov 123d18c1f26SAndrey V. Elsukov struct nat64lsn_alias { 124d18c1f26SAndrey V. Elsukov struct nat64lsn_aliaslink_slist hosts; 125d18c1f26SAndrey V. Elsukov struct nat64lsn_pg_slist portgroups; 126d18c1f26SAndrey V. Elsukov 127d18c1f26SAndrey V. Elsukov struct mtx lock; 128d18c1f26SAndrey V. Elsukov in_addr_t addr; /* host byte order */ 129d18c1f26SAndrey V. Elsukov uint32_t hosts_count; 130d18c1f26SAndrey V. Elsukov 131d18c1f26SAndrey V. Elsukov uint16_t timestamp; 132*4a77657cSAndrey V. Elsukov uint16_t tcp_pgcount; 133*4a77657cSAndrey V. Elsukov uint16_t udp_pgcount; 134*4a77657cSAndrey V. Elsukov uint16_t icmp_pgcount; 135*4a77657cSAndrey V. Elsukov /* 136*4a77657cSAndrey V. Elsukov * We keep PGs in chunks by 32 PGs in each. 137*4a77657cSAndrey V. Elsukov * Each chunk allocated by demand, and then corresponding bit 138*4a77657cSAndrey V. Elsukov * is set in chunkmask. 139*4a77657cSAndrey V. Elsukov * 140*4a77657cSAndrey V. Elsukov * Also we keep last used PG's index for each protocol. 141*4a77657cSAndrey V. Elsukov * pgidx / 32 = index of pgchunk; 142*4a77657cSAndrey V. Elsukov * pgidx % 32 = index of pgptr in pgchunk. 143*4a77657cSAndrey V. Elsukov */ 144*4a77657cSAndrey V. Elsukov uint32_t tcp_chunkmask; 145*4a77657cSAndrey V. Elsukov uint32_t tcp_pgidx; 146d18c1f26SAndrey V. Elsukov 147*4a77657cSAndrey V. Elsukov uint32_t udp_chunkmask; 148*4a77657cSAndrey V. Elsukov uint32_t udp_pgidx; 149*4a77657cSAndrey V. Elsukov 150*4a77657cSAndrey V. Elsukov uint32_t icmp_chunkmask; 151*4a77657cSAndrey V. Elsukov uint32_t icmp_pgidx; 152*4a77657cSAndrey V. Elsukov /* 153*4a77657cSAndrey V. Elsukov * Each pgchunk keeps 32 pointers to PGs. If pgptr pointer is 154*4a77657cSAndrey V. Elsukov * valid, we have corresponding bit set in the pgmask. 155*4a77657cSAndrey V. Elsukov */ 156d18c1f26SAndrey V. Elsukov uint32_t tcp_pgmask[32]; 157d18c1f26SAndrey V. Elsukov uint32_t udp_pgmask[32]; 158d18c1f26SAndrey V. Elsukov uint32_t icmp_pgmask[32]; 159*4a77657cSAndrey V. Elsukov 160d18c1f26SAndrey V. Elsukov struct nat64lsn_pgchunk *tcp[32]; 161d18c1f26SAndrey V. Elsukov struct nat64lsn_pgchunk *udp[32]; 162d18c1f26SAndrey V. Elsukov struct nat64lsn_pgchunk *icmp[32]; 163d18c1f26SAndrey V. Elsukov }; 164d18c1f26SAndrey V. Elsukov #define ALIAS_LOCK_INIT(p) \ 165d18c1f26SAndrey V. Elsukov mtx_init(&(p)->lock, "alias_lock", NULL, MTX_DEF) 166d18c1f26SAndrey V. Elsukov #define ALIAS_LOCK_DESTROY(p) mtx_destroy(&(p)->lock) 167d18c1f26SAndrey V. Elsukov #define ALIAS_LOCK(p) mtx_lock(&(p)->lock) 168d18c1f26SAndrey V. Elsukov #define ALIAS_UNLOCK(p) mtx_unlock(&(p)->lock) 169d18c1f26SAndrey V. Elsukov 170d18c1f26SAndrey V. Elsukov #define NAT64LSN_HSIZE 256 171d18c1f26SAndrey V. Elsukov #define NAT64LSN_MAX_HSIZE 4096 172d18c1f26SAndrey V. Elsukov #define NAT64LSN_HOSTS_HSIZE 1024 173d18c1f26SAndrey V. Elsukov 174d8caf56eSAndrey V. Elsukov struct nat64lsn_host { 175d8caf56eSAndrey V. Elsukov struct in6_addr addr; 176d18c1f26SAndrey V. Elsukov struct nat64lsn_aliaslink_slist aliases; 177d18c1f26SAndrey V. Elsukov struct nat64lsn_states_slist *states_hash; 178d18c1f26SAndrey V. Elsukov CK_SLIST_ENTRY(nat64lsn_host) entries; 179d18c1f26SAndrey V. Elsukov uint32_t states_count; 180d18c1f26SAndrey V. Elsukov uint32_t hval; 181d18c1f26SAndrey V. Elsukov uint32_t flags; 182d18c1f26SAndrey V. Elsukov #define NAT64LSN_DEADHOST 1 183d18c1f26SAndrey V. Elsukov #define NAT64LSN_GROWHASH 2 184d18c1f26SAndrey V. Elsukov uint16_t states_hashsize; 185d18c1f26SAndrey V. Elsukov uint16_t timestamp; 186d18c1f26SAndrey V. Elsukov struct mtx lock; 187d8caf56eSAndrey V. Elsukov }; 188d8caf56eSAndrey V. Elsukov 189d18c1f26SAndrey V. Elsukov #define HOST_LOCK_INIT(p) \ 190d18c1f26SAndrey V. Elsukov mtx_init(&(p)->lock, "host_lock", NULL, MTX_DEF|MTX_NEW) 191d18c1f26SAndrey V. Elsukov #define HOST_LOCK_DESTROY(p) mtx_destroy(&(p)->lock) 192d18c1f26SAndrey V. Elsukov #define HOST_LOCK(p) mtx_lock(&(p)->lock) 193d18c1f26SAndrey V. Elsukov #define HOST_UNLOCK(p) mtx_unlock(&(p)->lock) 194d8caf56eSAndrey V. Elsukov 195*4a77657cSAndrey V. Elsukov VNET_DECLARE(uint32_t, nat64lsn_eid); 196d8caf56eSAndrey V. Elsukov #define V_nat64lsn_eid VNET(nat64lsn_eid) 197d8caf56eSAndrey V. Elsukov #define IPFW_TLV_NAT64LSN_NAME IPFW_TLV_EACTION_NAME(V_nat64lsn_eid) 198d8caf56eSAndrey V. Elsukov 199d8caf56eSAndrey V. Elsukov /* Timestamp macro */ 200d8caf56eSAndrey V. Elsukov #define _CT ((int)time_uptime % 65536) 201d8caf56eSAndrey V. Elsukov #define SET_AGE(x) (x) = _CT 202d18c1f26SAndrey V. Elsukov #define GET_AGE(x) ((_CT >= (x)) ? _CT - (x): (int)65536 + _CT - (x)) 203d8caf56eSAndrey V. Elsukov 204d18c1f26SAndrey V. Elsukov STAILQ_HEAD(nat64lsn_job_head, nat64lsn_job_item); 205d8caf56eSAndrey V. Elsukov 206d8caf56eSAndrey V. Elsukov struct nat64lsn_cfg { 207d18c1f26SAndrey V. Elsukov struct nat64lsn_hosts_slist *hosts_hash; 208d18c1f26SAndrey V. Elsukov struct nat64lsn_alias *aliases; /* array of aliases */ 209d18c1f26SAndrey V. Elsukov 210d18c1f26SAndrey V. Elsukov struct mtx lock; 211d18c1f26SAndrey V. Elsukov uint32_t hosts_hashsize; 212d18c1f26SAndrey V. Elsukov uint32_t hash_seed; 213d18c1f26SAndrey V. Elsukov 214d8caf56eSAndrey V. Elsukov uint32_t prefix4; /* IPv4 prefix */ 215d8caf56eSAndrey V. Elsukov uint32_t pmask4; /* IPv4 prefix mask */ 216d8caf56eSAndrey V. Elsukov uint8_t plen4; 217d18c1f26SAndrey V. Elsukov uint8_t nomatch_verdict;/* Return value on no-match */ 218d8caf56eSAndrey V. Elsukov 219d18c1f26SAndrey V. Elsukov uint32_t hosts_count; /* Number of items in host hash */ 220d18c1f26SAndrey V. Elsukov uint32_t states_chunks; /* Number of states chunks per PG */ 221d8caf56eSAndrey V. Elsukov uint32_t jmaxlen; /* Max jobqueue length */ 222d18c1f26SAndrey V. Elsukov uint16_t host_delete_delay; /* Stale host delete delay */ 223d18c1f26SAndrey V. Elsukov uint16_t pgchunk_delete_delay; 224d8caf56eSAndrey V. Elsukov uint16_t pg_delete_delay; /* Stale portgroup del delay */ 225d8caf56eSAndrey V. Elsukov uint16_t st_syn_ttl; /* TCP syn expire */ 226d8caf56eSAndrey V. Elsukov uint16_t st_close_ttl; /* TCP fin expire */ 227d8caf56eSAndrey V. Elsukov uint16_t st_estab_ttl; /* TCP established expire */ 228d8caf56eSAndrey V. Elsukov uint16_t st_udp_ttl; /* UDP expire */ 229d8caf56eSAndrey V. Elsukov uint16_t st_icmp_ttl; /* ICMP expire */ 230d18c1f26SAndrey V. Elsukov 231782360deSAndrey V. Elsukov struct nat64_config base; 232*4a77657cSAndrey V. Elsukov #define NAT64LSN_FLAGSMASK (NAT64_LOG | NAT64_ALLOW_PRIVATE | \ 233*4a77657cSAndrey V. Elsukov NAT64LSN_ALLOW_SWAPCONF) 234d18c1f26SAndrey V. Elsukov #define NAT64LSN_ANYPREFIX 0x00000100 235d8caf56eSAndrey V. Elsukov 236d18c1f26SAndrey V. Elsukov struct mtx periodic_lock; 237d8caf56eSAndrey V. Elsukov struct callout periodic; 238d8caf56eSAndrey V. Elsukov struct callout jcallout; 239d8caf56eSAndrey V. Elsukov struct vnet *vp; 240d8caf56eSAndrey V. Elsukov struct nat64lsn_job_head jhead; 241d8caf56eSAndrey V. Elsukov int jlen; 242d8caf56eSAndrey V. Elsukov char name[64]; /* Nat instance name */ 243d8caf56eSAndrey V. Elsukov }; 244d8caf56eSAndrey V. Elsukov 245*4a77657cSAndrey V. Elsukov struct nat64lsn_instance { 246*4a77657cSAndrey V. Elsukov struct named_object no; 247*4a77657cSAndrey V. Elsukov struct nat64lsn_cfg *cfg; 248*4a77657cSAndrey V. Elsukov char name[64]; /* Nat instance name */ 249*4a77657cSAndrey V. Elsukov }; 250*4a77657cSAndrey V. Elsukov 251d18c1f26SAndrey V. Elsukov /* CFG_LOCK protects cfg->hosts_hash from modification */ 252d18c1f26SAndrey V. Elsukov #define CFG_LOCK_INIT(p) \ 253d18c1f26SAndrey V. Elsukov mtx_init(&(p)->lock, "cfg_lock", NULL, MTX_DEF) 254d18c1f26SAndrey V. Elsukov #define CFG_LOCK_DESTROY(p) mtx_destroy(&(p)->lock) 255d18c1f26SAndrey V. Elsukov #define CFG_LOCK(p) mtx_lock(&(p)->lock) 256d18c1f26SAndrey V. Elsukov #define CFG_UNLOCK(p) mtx_unlock(&(p)->lock) 257d18c1f26SAndrey V. Elsukov 258d18c1f26SAndrey V. Elsukov #define CALLOUT_LOCK_INIT(p) \ 259d18c1f26SAndrey V. Elsukov mtx_init(&(p)->periodic_lock, "periodic_lock", NULL, MTX_DEF) 260d18c1f26SAndrey V. Elsukov #define CALLOUT_LOCK_DESTROY(p) mtx_destroy(&(p)->periodic_lock) 261d18c1f26SAndrey V. Elsukov #define CALLOUT_LOCK(p) mtx_lock(&(p)->periodic_lock) 262d18c1f26SAndrey V. Elsukov #define CALLOUT_UNLOCK(p) mtx_unlock(&(p)->periodic_lock) 263d18c1f26SAndrey V. Elsukov 264*4a77657cSAndrey V. Elsukov MALLOC_DECLARE(M_NAT64LSN); 265*4a77657cSAndrey V. Elsukov 266*4a77657cSAndrey V. Elsukov struct nat64lsn_cfg *nat64lsn_init_config(struct ip_fw_chain *ch, 267d18c1f26SAndrey V. Elsukov in_addr_t prefix, int plen); 268*4a77657cSAndrey V. Elsukov void nat64lsn_destroy_config(struct nat64lsn_cfg *cfg); 269d8caf56eSAndrey V. Elsukov void nat64lsn_start_instance(struct nat64lsn_cfg *cfg); 270d8caf56eSAndrey V. Elsukov void nat64lsn_init_internal(void); 271d8caf56eSAndrey V. Elsukov void nat64lsn_uninit_internal(void); 272d8caf56eSAndrey V. Elsukov int ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args, 273d8caf56eSAndrey V. Elsukov ipfw_insn *cmd, int *done); 274d8caf56eSAndrey V. Elsukov 275d8caf56eSAndrey V. Elsukov #endif /* _IP_FW_NAT64LSN_H_ */ 276