| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | #ifndef _TCP_AO_H |
| 3 | #define _TCP_AO_H |
| 4 | |
| 5 | #define TCP_AO_KEY_ALIGN 1 |
| 6 | #define __tcp_ao_key_align __aligned(TCP_AO_KEY_ALIGN) |
| 7 | |
| 8 | union tcp_ao_addr { |
| 9 | struct in_addr a4; |
| 10 | #if IS_ENABLED(CONFIG_IPV6) |
| 11 | struct in6_addr a6; |
| 12 | #endif |
| 13 | }; |
| 14 | |
| 15 | struct tcp_ao_hdr { |
| 16 | u8 kind; |
| 17 | u8 length; |
| 18 | u8 keyid; |
| 19 | u8 rnext_keyid; |
| 20 | }; |
| 21 | |
| 22 | static inline u8 tcp_ao_hdr_maclen(const struct tcp_ao_hdr *aoh) |
| 23 | { |
| 24 | return aoh->length - sizeof(struct tcp_ao_hdr); |
| 25 | } |
| 26 | |
| 27 | struct tcp_ao_counters { |
| 28 | atomic64_t pkt_good; |
| 29 | atomic64_t pkt_bad; |
| 30 | atomic64_t key_not_found; |
| 31 | atomic64_t ao_required; |
| 32 | atomic64_t dropped_icmp; |
| 33 | }; |
| 34 | |
| 35 | struct tcp_ao_key { |
| 36 | struct hlist_node node; |
| 37 | union tcp_ao_addr addr; |
| 38 | u8 key[TCP_AO_MAXKEYLEN] __tcp_ao_key_align; |
| 39 | unsigned int tcp_sigpool_id; |
| 40 | unsigned int digest_size; |
| 41 | int l3index; |
| 42 | u8 prefixlen; |
| 43 | u8 family; |
| 44 | u8 keylen; |
| 45 | u8 keyflags; |
| 46 | u8 sndid; |
| 47 | u8 rcvid; |
| 48 | u8 maclen; |
| 49 | struct rcu_head rcu; |
| 50 | atomic64_t pkt_good; |
| 51 | atomic64_t pkt_bad; |
| 52 | u8 traffic_keys[]; |
| 53 | }; |
| 54 | |
| 55 | static inline u8 *rcv_other_key(struct tcp_ao_key *key) |
| 56 | { |
| 57 | return key->traffic_keys; |
| 58 | } |
| 59 | |
| 60 | static inline u8 *snd_other_key(struct tcp_ao_key *key) |
| 61 | { |
| 62 | return key->traffic_keys + key->digest_size; |
| 63 | } |
| 64 | |
| 65 | static inline int tcp_ao_maclen(const struct tcp_ao_key *key) |
| 66 | { |
| 67 | return key->maclen; |
| 68 | } |
| 69 | |
| 70 | /* Use tcp_ao_len_aligned() for TCP header calculations */ |
| 71 | static inline int tcp_ao_len(const struct tcp_ao_key *key) |
| 72 | { |
| 73 | return tcp_ao_maclen(key) + sizeof(struct tcp_ao_hdr); |
| 74 | } |
| 75 | |
| 76 | static inline int tcp_ao_len_aligned(const struct tcp_ao_key *key) |
| 77 | { |
| 78 | return round_up(tcp_ao_len(key), 4); |
| 79 | } |
| 80 | |
| 81 | static inline unsigned int tcp_ao_digest_size(struct tcp_ao_key *key) |
| 82 | { |
| 83 | return key->digest_size; |
| 84 | } |
| 85 | |
| 86 | static inline int tcp_ao_sizeof_key(const struct tcp_ao_key *key) |
| 87 | { |
| 88 | return sizeof(struct tcp_ao_key) + (key->digest_size << 1); |
| 89 | } |
| 90 | |
| 91 | struct tcp_ao_info { |
| 92 | /* List of tcp_ao_key's */ |
| 93 | struct hlist_head head; |
| 94 | /* current_key and rnext_key are maintained on sockets |
| 95 | * in TCP_AO_ESTABLISHED states. |
| 96 | * Their purpose is to cache keys on established connections, |
| 97 | * saving needless lookups. Never dereference any of them from |
| 98 | * listen sockets. |
| 99 | * ::current_key may change in RX to the key that was requested by |
| 100 | * the peer, please use READ_ONCE()/WRITE_ONCE() in order to avoid |
| 101 | * load/store tearing. |
| 102 | * Do the same for ::rnext_key, if you don't hold socket lock |
| 103 | * (it's changed only by userspace request in setsockopt()). |
| 104 | */ |
| 105 | struct tcp_ao_key *current_key; |
| 106 | struct tcp_ao_key *rnext_key; |
| 107 | struct tcp_ao_counters counters; |
| 108 | u32 ao_required :1, |
| 109 | accept_icmps :1, |
| 110 | __unused :30; |
| 111 | __be32 lisn; |
| 112 | __be32 risn; |
| 113 | /* Sequence Number Extension (SNE) are upper 4 bytes for SEQ, |
| 114 | * that protect TCP-AO connection from replayed old TCP segments. |
| 115 | * See RFC5925 (6.2). |
| 116 | * In order to get correct SNE, there's a helper tcp_ao_compute_sne(). |
| 117 | * It needs SEQ basis to understand whereabouts are lower SEQ numbers. |
| 118 | * According to that basis vector, it can provide incremented SNE |
| 119 | * when SEQ rolls over or provide decremented SNE when there's |
| 120 | * a retransmitted segment from before-rolling over. |
| 121 | * - for request sockets such basis is rcv_isn/snt_isn, which seems |
| 122 | * good enough as it's unexpected to receive 4 Gbytes on reqsk. |
| 123 | * - for full sockets the basis is rcv_nxt/snd_una. snd_una is |
| 124 | * taken instead of snd_nxt as currently it's easier to track |
| 125 | * in tcp_snd_una_update(), rather than updating SNE in all |
| 126 | * WRITE_ONCE(tp->snd_nxt, ...) |
| 127 | * - for time-wait sockets the basis is tw_rcv_nxt/tw_snd_nxt. |
| 128 | * tw_snd_nxt is not expected to change, while tw_rcv_nxt may. |
| 129 | */ |
| 130 | u32 snd_sne; |
| 131 | u32 rcv_sne; |
| 132 | refcount_t refcnt; /* Protects twsk destruction */ |
| 133 | }; |
| 134 | |
| 135 | #ifdef CONFIG_TCP_MD5SIG |
| 136 | #include <linux/jump_label.h> |
| 137 | extern struct static_key_false_deferred tcp_md5_needed; |
| 138 | #define static_branch_tcp_md5() static_branch_unlikely(&tcp_md5_needed.key) |
| 139 | #else |
| 140 | #define static_branch_tcp_md5() false |
| 141 | #endif |
| 142 | #ifdef CONFIG_TCP_AO |
| 143 | /* TCP-AO structures and functions */ |
| 144 | #include <linux/jump_label.h> |
| 145 | extern struct static_key_false_deferred tcp_ao_needed; |
| 146 | #define static_branch_tcp_ao() static_branch_unlikely(&tcp_ao_needed.key) |
| 147 | #else |
| 148 | #define static_branch_tcp_ao() false |
| 149 | #endif |
| 150 | |
| 151 | #ifdef CONFIG_TCP_AO |
| 152 | /* TCP-AO structures and functions */ |
| 153 | struct tcp4_ao_context { |
| 154 | __be32 saddr; |
| 155 | __be32 daddr; |
| 156 | __be16 sport; |
| 157 | __be16 dport; |
| 158 | __be32 sisn; |
| 159 | __be32 disn; |
| 160 | }; |
| 161 | |
| 162 | struct tcp6_ao_context { |
| 163 | struct in6_addr saddr; |
| 164 | struct in6_addr daddr; |
| 165 | __be16 sport; |
| 166 | __be16 dport; |
| 167 | __be32 sisn; |
| 168 | __be32 disn; |
| 169 | }; |
| 170 | |
| 171 | struct tcp_sigpool; |
| 172 | /* Established states are fast-path and there always is current_key/rnext_key */ |
| 173 | #define TCP_AO_ESTABLISHED (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2 | \ |
| 174 | TCPF_CLOSE_WAIT | TCPF_LAST_ACK | TCPF_CLOSING) |
| 175 | |
| 176 | int tcp_ao_transmit_skb(struct sock *sk, struct sk_buff *skb, |
| 177 | struct tcp_ao_key *key, struct tcphdr *th, |
| 178 | __u8 *hash_location); |
| 179 | int tcp_ao_hash_skb(unsigned short int family, |
| 180 | char *ao_hash, struct tcp_ao_key *key, |
| 181 | const struct sock *sk, const struct sk_buff *skb, |
| 182 | const u8 *tkey, int hash_offset, u32 sne); |
| 183 | int tcp_parse_ao(struct sock *sk, int cmd, unsigned short int family, |
| 184 | sockptr_t optval, int optlen); |
| 185 | struct tcp_ao_key *tcp_ao_established_key(const struct sock *sk, |
| 186 | struct tcp_ao_info *ao, |
| 187 | int sndid, int rcvid); |
| 188 | int tcp_ao_copy_all_matching(const struct sock *sk, struct sock *newsk, |
| 189 | struct request_sock *req, struct sk_buff *skb, |
| 190 | int family); |
| 191 | int tcp_ao_calc_traffic_key(struct tcp_ao_key *mkt, u8 *key, void *ctx, |
| 192 | unsigned int len, struct tcp_sigpool *hp); |
| 193 | void tcp_ao_destroy_sock(struct sock *sk, bool twsk); |
| 194 | void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp); |
| 195 | bool tcp_ao_ignore_icmp(const struct sock *sk, int family, int type, int code); |
| 196 | int tcp_ao_get_mkts(struct sock *sk, sockptr_t optval, sockptr_t optlen); |
| 197 | int tcp_ao_get_sock_info(struct sock *sk, sockptr_t optval, sockptr_t optlen); |
| 198 | int tcp_ao_get_repair(struct sock *sk, sockptr_t optval, sockptr_t optlen); |
| 199 | int tcp_ao_set_repair(struct sock *sk, sockptr_t optval, unsigned int optlen); |
| 200 | enum skb_drop_reason tcp_inbound_ao_hash(struct sock *sk, |
| 201 | const struct sk_buff *skb, unsigned short int family, |
| 202 | const struct request_sock *req, int l3index, |
| 203 | const struct tcp_ao_hdr *aoh); |
| 204 | u32 tcp_ao_compute_sne(u32 next_sne, u32 next_seq, u32 seq); |
| 205 | struct tcp_ao_key *tcp_ao_do_lookup(const struct sock *sk, int l3index, |
| 206 | const union tcp_ao_addr *addr, |
| 207 | int family, int sndid, int rcvid); |
| 208 | int tcp_ao_hash_hdr(unsigned short family, char *ao_hash, |
| 209 | struct tcp_ao_key *key, const u8 *tkey, |
| 210 | const union tcp_ao_addr *daddr, |
| 211 | const union tcp_ao_addr *saddr, |
| 212 | const struct tcphdr *th, u32 sne); |
| 213 | int tcp_ao_prepare_reset(const struct sock *sk, struct sk_buff *skb, |
| 214 | const struct tcp_ao_hdr *aoh, int l3index, u32 seq, |
| 215 | struct tcp_ao_key **key, char **traffic_key, |
| 216 | bool *allocated_traffic_key, u8 *keyid, u32 *sne); |
| 217 | |
| 218 | /* ipv4 specific functions */ |
| 219 | int tcp_v4_parse_ao(struct sock *sk, int cmd, sockptr_t optval, int optlen); |
| 220 | struct tcp_ao_key *tcp_v4_ao_lookup(const struct sock *sk, struct sock *addr_sk, |
| 221 | int sndid, int rcvid); |
| 222 | int tcp_v4_ao_synack_hash(char *ao_hash, struct tcp_ao_key *mkt, |
| 223 | struct request_sock *req, const struct sk_buff *skb, |
| 224 | int hash_offset, u32 sne); |
| 225 | int tcp_v4_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key, |
| 226 | const struct sock *sk, |
| 227 | __be32 sisn, __be32 disn, bool send); |
| 228 | int tcp_v4_ao_calc_key_rsk(struct tcp_ao_key *mkt, u8 *key, |
| 229 | struct request_sock *req); |
| 230 | struct tcp_ao_key *tcp_v4_ao_lookup_rsk(const struct sock *sk, |
| 231 | struct request_sock *req, |
| 232 | int sndid, int rcvid); |
| 233 | int tcp_v4_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key, |
| 234 | const struct sock *sk, const struct sk_buff *skb, |
| 235 | const u8 *tkey, int hash_offset, u32 sne); |
| 236 | /* ipv6 specific functions */ |
| 237 | int (struct tcp_sigpool *hp, |
| 238 | const struct in6_addr *daddr, |
| 239 | const struct in6_addr *saddr, int nbytes); |
| 240 | int tcp_v6_ao_calc_key_skb(struct tcp_ao_key *mkt, u8 *key, |
| 241 | const struct sk_buff *skb, __be32 sisn, __be32 disn); |
| 242 | int tcp_v6_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key, |
| 243 | const struct sock *sk, __be32 sisn, |
| 244 | __be32 disn, bool send); |
| 245 | int tcp_v6_ao_calc_key_rsk(struct tcp_ao_key *mkt, u8 *key, |
| 246 | struct request_sock *req); |
| 247 | struct tcp_ao_key *tcp_v6_ao_lookup(const struct sock *sk, |
| 248 | struct sock *addr_sk, int sndid, int rcvid); |
| 249 | struct tcp_ao_key *tcp_v6_ao_lookup_rsk(const struct sock *sk, |
| 250 | struct request_sock *req, |
| 251 | int sndid, int rcvid); |
| 252 | int tcp_v6_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key, |
| 253 | const struct sock *sk, const struct sk_buff *skb, |
| 254 | const u8 *tkey, int hash_offset, u32 sne); |
| 255 | int tcp_v6_parse_ao(struct sock *sk, int cmd, sockptr_t optval, int optlen); |
| 256 | int tcp_v6_ao_synack_hash(char *ao_hash, struct tcp_ao_key *ao_key, |
| 257 | struct request_sock *req, const struct sk_buff *skb, |
| 258 | int hash_offset, u32 sne); |
| 259 | void tcp_ao_established(struct sock *sk); |
| 260 | void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb); |
| 261 | void tcp_ao_connect_init(struct sock *sk); |
| 262 | void tcp_ao_syncookie(struct sock *sk, const struct sk_buff *skb, |
| 263 | struct request_sock *req, unsigned short int family); |
| 264 | #else /* CONFIG_TCP_AO */ |
| 265 | |
| 266 | static inline int tcp_ao_transmit_skb(struct sock *sk, struct sk_buff *skb, |
| 267 | struct tcp_ao_key *key, struct tcphdr *th, |
| 268 | __u8 *hash_location) |
| 269 | { |
| 270 | return 0; |
| 271 | } |
| 272 | |
| 273 | static inline void tcp_ao_syncookie(struct sock *sk, const struct sk_buff *skb, |
| 274 | struct request_sock *req, unsigned short int family) |
| 275 | { |
| 276 | } |
| 277 | |
| 278 | static inline bool tcp_ao_ignore_icmp(const struct sock *sk, int family, |
| 279 | int type, int code) |
| 280 | { |
| 281 | return false; |
| 282 | } |
| 283 | |
| 284 | static inline enum skb_drop_reason tcp_inbound_ao_hash(struct sock *sk, |
| 285 | const struct sk_buff *skb, unsigned short int family, |
| 286 | const struct request_sock *req, int l3index, |
| 287 | const struct tcp_ao_hdr *aoh) |
| 288 | { |
| 289 | return SKB_NOT_DROPPED_YET; |
| 290 | } |
| 291 | |
| 292 | static inline struct tcp_ao_key *tcp_ao_do_lookup(const struct sock *sk, |
| 293 | int l3index, const union tcp_ao_addr *addr, |
| 294 | int family, int sndid, int rcvid) |
| 295 | { |
| 296 | return NULL; |
| 297 | } |
| 298 | |
| 299 | static inline void tcp_ao_destroy_sock(struct sock *sk, bool twsk) |
| 300 | { |
| 301 | } |
| 302 | |
| 303 | static inline void tcp_ao_established(struct sock *sk) |
| 304 | { |
| 305 | } |
| 306 | |
| 307 | static inline void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb) |
| 308 | { |
| 309 | } |
| 310 | |
| 311 | static inline void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, |
| 312 | struct tcp_sock *tp) |
| 313 | { |
| 314 | } |
| 315 | |
| 316 | static inline void tcp_ao_connect_init(struct sock *sk) |
| 317 | { |
| 318 | } |
| 319 | |
| 320 | static inline int tcp_ao_get_mkts(struct sock *sk, sockptr_t optval, sockptr_t optlen) |
| 321 | { |
| 322 | return -ENOPROTOOPT; |
| 323 | } |
| 324 | |
| 325 | static inline int tcp_ao_get_sock_info(struct sock *sk, sockptr_t optval, sockptr_t optlen) |
| 326 | { |
| 327 | return -ENOPROTOOPT; |
| 328 | } |
| 329 | |
| 330 | static inline int tcp_ao_get_repair(struct sock *sk, |
| 331 | sockptr_t optval, sockptr_t optlen) |
| 332 | { |
| 333 | return -ENOPROTOOPT; |
| 334 | } |
| 335 | |
| 336 | static inline int tcp_ao_set_repair(struct sock *sk, |
| 337 | sockptr_t optval, unsigned int optlen) |
| 338 | { |
| 339 | return -ENOPROTOOPT; |
| 340 | } |
| 341 | #endif |
| 342 | |
| 343 | #if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO) |
| 344 | int tcp_do_parse_auth_options(const struct tcphdr *th, |
| 345 | const u8 **md5_hash, const u8 **ao_hash); |
| 346 | #else |
| 347 | static inline int tcp_do_parse_auth_options(const struct tcphdr *th, |
| 348 | const u8 **md5_hash, const u8 **ao_hash) |
| 349 | { |
| 350 | *md5_hash = NULL; |
| 351 | *ao_hash = NULL; |
| 352 | return 0; |
| 353 | } |
| 354 | #endif |
| 355 | |
| 356 | #endif /* _TCP_AO_H */ |
| 357 | |