Commit c1e2e04388b2539960453689b8e721709f71dc9c
Committed by
Patrick McHardy
1 parent
ac8cc925d3
Exists in
master
and in
6 other branches
netfilter: ipset: support listing setnames and headers too
Current listing makes possible to list sets with full content only. The patch adds support partial listings, i.e. listing just the existing setnames or listing set headers, without set members. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Patrick McHardy <kaber@trash.net>
Showing 2 changed files with 50 additions and 27 deletions Inline Diff
include/linux/netfilter/ipset/ip_set.h
1 | #ifndef _IP_SET_H | 1 | #ifndef _IP_SET_H |
2 | #define _IP_SET_H | 2 | #define _IP_SET_H |
3 | 3 | ||
4 | /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> | 4 | /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> |
5 | * Patrick Schaaf <bof@bof.de> | 5 | * Patrick Schaaf <bof@bof.de> |
6 | * Martin Josefsson <gandalf@wlug.westbo.se> | 6 | * Martin Josefsson <gandalf@wlug.westbo.se> |
7 | * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 7 | * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | /* The protocol version */ | 14 | /* The protocol version */ |
15 | #define IPSET_PROTOCOL 6 | 15 | #define IPSET_PROTOCOL 6 |
16 | 16 | ||
17 | /* The max length of strings including NUL: set and type identifiers */ | 17 | /* The max length of strings including NUL: set and type identifiers */ |
18 | #define IPSET_MAXNAMELEN 32 | 18 | #define IPSET_MAXNAMELEN 32 |
19 | 19 | ||
20 | /* Message types and commands */ | 20 | /* Message types and commands */ |
21 | enum ipset_cmd { | 21 | enum ipset_cmd { |
22 | IPSET_CMD_NONE, | 22 | IPSET_CMD_NONE, |
23 | IPSET_CMD_PROTOCOL, /* 1: Return protocol version */ | 23 | IPSET_CMD_PROTOCOL, /* 1: Return protocol version */ |
24 | IPSET_CMD_CREATE, /* 2: Create a new (empty) set */ | 24 | IPSET_CMD_CREATE, /* 2: Create a new (empty) set */ |
25 | IPSET_CMD_DESTROY, /* 3: Destroy a (empty) set */ | 25 | IPSET_CMD_DESTROY, /* 3: Destroy a (empty) set */ |
26 | IPSET_CMD_FLUSH, /* 4: Remove all elements from a set */ | 26 | IPSET_CMD_FLUSH, /* 4: Remove all elements from a set */ |
27 | IPSET_CMD_RENAME, /* 5: Rename a set */ | 27 | IPSET_CMD_RENAME, /* 5: Rename a set */ |
28 | IPSET_CMD_SWAP, /* 6: Swap two sets */ | 28 | IPSET_CMD_SWAP, /* 6: Swap two sets */ |
29 | IPSET_CMD_LIST, /* 7: List sets */ | 29 | IPSET_CMD_LIST, /* 7: List sets */ |
30 | IPSET_CMD_SAVE, /* 8: Save sets */ | 30 | IPSET_CMD_SAVE, /* 8: Save sets */ |
31 | IPSET_CMD_ADD, /* 9: Add an element to a set */ | 31 | IPSET_CMD_ADD, /* 9: Add an element to a set */ |
32 | IPSET_CMD_DEL, /* 10: Delete an element from a set */ | 32 | IPSET_CMD_DEL, /* 10: Delete an element from a set */ |
33 | IPSET_CMD_TEST, /* 11: Test an element in a set */ | 33 | IPSET_CMD_TEST, /* 11: Test an element in a set */ |
34 | IPSET_CMD_HEADER, /* 12: Get set header data only */ | 34 | IPSET_CMD_HEADER, /* 12: Get set header data only */ |
35 | IPSET_CMD_TYPE, /* 13: Get set type */ | 35 | IPSET_CMD_TYPE, /* 13: Get set type */ |
36 | IPSET_MSG_MAX, /* Netlink message commands */ | 36 | IPSET_MSG_MAX, /* Netlink message commands */ |
37 | 37 | ||
38 | /* Commands in userspace: */ | 38 | /* Commands in userspace: */ |
39 | IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */ | 39 | IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */ |
40 | IPSET_CMD_HELP, /* 15: Get help */ | 40 | IPSET_CMD_HELP, /* 15: Get help */ |
41 | IPSET_CMD_VERSION, /* 16: Get program version */ | 41 | IPSET_CMD_VERSION, /* 16: Get program version */ |
42 | IPSET_CMD_QUIT, /* 17: Quit from interactive mode */ | 42 | IPSET_CMD_QUIT, /* 17: Quit from interactive mode */ |
43 | 43 | ||
44 | IPSET_CMD_MAX, | 44 | IPSET_CMD_MAX, |
45 | 45 | ||
46 | IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */ | 46 | IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */ |
47 | }; | 47 | }; |
48 | 48 | ||
49 | /* Attributes at command level */ | 49 | /* Attributes at command level */ |
50 | enum { | 50 | enum { |
51 | IPSET_ATTR_UNSPEC, | 51 | IPSET_ATTR_UNSPEC, |
52 | IPSET_ATTR_PROTOCOL, /* 1: Protocol version */ | 52 | IPSET_ATTR_PROTOCOL, /* 1: Protocol version */ |
53 | IPSET_ATTR_SETNAME, /* 2: Name of the set */ | 53 | IPSET_ATTR_SETNAME, /* 2: Name of the set */ |
54 | IPSET_ATTR_TYPENAME, /* 3: Typename */ | 54 | IPSET_ATTR_TYPENAME, /* 3: Typename */ |
55 | IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* Setname at rename/swap */ | 55 | IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* Setname at rename/swap */ |
56 | IPSET_ATTR_REVISION, /* 4: Settype revision */ | 56 | IPSET_ATTR_REVISION, /* 4: Settype revision */ |
57 | IPSET_ATTR_FAMILY, /* 5: Settype family */ | 57 | IPSET_ATTR_FAMILY, /* 5: Settype family */ |
58 | IPSET_ATTR_FLAGS, /* 6: Flags at command level */ | 58 | IPSET_ATTR_FLAGS, /* 6: Flags at command level */ |
59 | IPSET_ATTR_DATA, /* 7: Nested attributes */ | 59 | IPSET_ATTR_DATA, /* 7: Nested attributes */ |
60 | IPSET_ATTR_ADT, /* 8: Multiple data containers */ | 60 | IPSET_ATTR_ADT, /* 8: Multiple data containers */ |
61 | IPSET_ATTR_LINENO, /* 9: Restore lineno */ | 61 | IPSET_ATTR_LINENO, /* 9: Restore lineno */ |
62 | IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */ | 62 | IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */ |
63 | IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */ | 63 | IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */ |
64 | __IPSET_ATTR_CMD_MAX, | 64 | __IPSET_ATTR_CMD_MAX, |
65 | }; | 65 | }; |
66 | #define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1) | 66 | #define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1) |
67 | 67 | ||
68 | /* CADT specific attributes */ | 68 | /* CADT specific attributes */ |
69 | enum { | 69 | enum { |
70 | IPSET_ATTR_IP = IPSET_ATTR_UNSPEC + 1, | 70 | IPSET_ATTR_IP = IPSET_ATTR_UNSPEC + 1, |
71 | IPSET_ATTR_IP_FROM = IPSET_ATTR_IP, | 71 | IPSET_ATTR_IP_FROM = IPSET_ATTR_IP, |
72 | IPSET_ATTR_IP_TO, /* 2 */ | 72 | IPSET_ATTR_IP_TO, /* 2 */ |
73 | IPSET_ATTR_CIDR, /* 3 */ | 73 | IPSET_ATTR_CIDR, /* 3 */ |
74 | IPSET_ATTR_PORT, /* 4 */ | 74 | IPSET_ATTR_PORT, /* 4 */ |
75 | IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT, | 75 | IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT, |
76 | IPSET_ATTR_PORT_TO, /* 5 */ | 76 | IPSET_ATTR_PORT_TO, /* 5 */ |
77 | IPSET_ATTR_TIMEOUT, /* 6 */ | 77 | IPSET_ATTR_TIMEOUT, /* 6 */ |
78 | IPSET_ATTR_PROTO, /* 7 */ | 78 | IPSET_ATTR_PROTO, /* 7 */ |
79 | IPSET_ATTR_CADT_FLAGS, /* 8 */ | 79 | IPSET_ATTR_CADT_FLAGS, /* 8 */ |
80 | IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */ | 80 | IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */ |
81 | /* Reserve empty slots */ | 81 | /* Reserve empty slots */ |
82 | IPSET_ATTR_CADT_MAX = 16, | 82 | IPSET_ATTR_CADT_MAX = 16, |
83 | /* Create-only specific attributes */ | 83 | /* Create-only specific attributes */ |
84 | IPSET_ATTR_GC, | 84 | IPSET_ATTR_GC, |
85 | IPSET_ATTR_HASHSIZE, | 85 | IPSET_ATTR_HASHSIZE, |
86 | IPSET_ATTR_MAXELEM, | 86 | IPSET_ATTR_MAXELEM, |
87 | IPSET_ATTR_NETMASK, | 87 | IPSET_ATTR_NETMASK, |
88 | IPSET_ATTR_PROBES, | 88 | IPSET_ATTR_PROBES, |
89 | IPSET_ATTR_RESIZE, | 89 | IPSET_ATTR_RESIZE, |
90 | IPSET_ATTR_SIZE, | 90 | IPSET_ATTR_SIZE, |
91 | /* Kernel-only */ | 91 | /* Kernel-only */ |
92 | IPSET_ATTR_ELEMENTS, | 92 | IPSET_ATTR_ELEMENTS, |
93 | IPSET_ATTR_REFERENCES, | 93 | IPSET_ATTR_REFERENCES, |
94 | IPSET_ATTR_MEMSIZE, | 94 | IPSET_ATTR_MEMSIZE, |
95 | 95 | ||
96 | __IPSET_ATTR_CREATE_MAX, | 96 | __IPSET_ATTR_CREATE_MAX, |
97 | }; | 97 | }; |
98 | #define IPSET_ATTR_CREATE_MAX (__IPSET_ATTR_CREATE_MAX - 1) | 98 | #define IPSET_ATTR_CREATE_MAX (__IPSET_ATTR_CREATE_MAX - 1) |
99 | 99 | ||
100 | /* ADT specific attributes */ | 100 | /* ADT specific attributes */ |
101 | enum { | 101 | enum { |
102 | IPSET_ATTR_ETHER = IPSET_ATTR_CADT_MAX + 1, | 102 | IPSET_ATTR_ETHER = IPSET_ATTR_CADT_MAX + 1, |
103 | IPSET_ATTR_NAME, | 103 | IPSET_ATTR_NAME, |
104 | IPSET_ATTR_NAMEREF, | 104 | IPSET_ATTR_NAMEREF, |
105 | IPSET_ATTR_IP2, | 105 | IPSET_ATTR_IP2, |
106 | IPSET_ATTR_CIDR2, | 106 | IPSET_ATTR_CIDR2, |
107 | __IPSET_ATTR_ADT_MAX, | 107 | __IPSET_ATTR_ADT_MAX, |
108 | }; | 108 | }; |
109 | #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) | 109 | #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) |
110 | 110 | ||
111 | /* IP specific attributes */ | 111 | /* IP specific attributes */ |
112 | enum { | 112 | enum { |
113 | IPSET_ATTR_IPADDR_IPV4 = IPSET_ATTR_UNSPEC + 1, | 113 | IPSET_ATTR_IPADDR_IPV4 = IPSET_ATTR_UNSPEC + 1, |
114 | IPSET_ATTR_IPADDR_IPV6, | 114 | IPSET_ATTR_IPADDR_IPV6, |
115 | __IPSET_ATTR_IPADDR_MAX, | 115 | __IPSET_ATTR_IPADDR_MAX, |
116 | }; | 116 | }; |
117 | #define IPSET_ATTR_IPADDR_MAX (__IPSET_ATTR_IPADDR_MAX - 1) | 117 | #define IPSET_ATTR_IPADDR_MAX (__IPSET_ATTR_IPADDR_MAX - 1) |
118 | 118 | ||
119 | /* Error codes */ | 119 | /* Error codes */ |
120 | enum ipset_errno { | 120 | enum ipset_errno { |
121 | IPSET_ERR_PRIVATE = 4096, | 121 | IPSET_ERR_PRIVATE = 4096, |
122 | IPSET_ERR_PROTOCOL, | 122 | IPSET_ERR_PROTOCOL, |
123 | IPSET_ERR_FIND_TYPE, | 123 | IPSET_ERR_FIND_TYPE, |
124 | IPSET_ERR_MAX_SETS, | 124 | IPSET_ERR_MAX_SETS, |
125 | IPSET_ERR_BUSY, | 125 | IPSET_ERR_BUSY, |
126 | IPSET_ERR_EXIST_SETNAME2, | 126 | IPSET_ERR_EXIST_SETNAME2, |
127 | IPSET_ERR_TYPE_MISMATCH, | 127 | IPSET_ERR_TYPE_MISMATCH, |
128 | IPSET_ERR_EXIST, | 128 | IPSET_ERR_EXIST, |
129 | IPSET_ERR_INVALID_CIDR, | 129 | IPSET_ERR_INVALID_CIDR, |
130 | IPSET_ERR_INVALID_NETMASK, | 130 | IPSET_ERR_INVALID_NETMASK, |
131 | IPSET_ERR_INVALID_FAMILY, | 131 | IPSET_ERR_INVALID_FAMILY, |
132 | IPSET_ERR_TIMEOUT, | 132 | IPSET_ERR_TIMEOUT, |
133 | IPSET_ERR_REFERENCED, | 133 | IPSET_ERR_REFERENCED, |
134 | IPSET_ERR_IPADDR_IPV4, | 134 | IPSET_ERR_IPADDR_IPV4, |
135 | IPSET_ERR_IPADDR_IPV6, | 135 | IPSET_ERR_IPADDR_IPV6, |
136 | 136 | ||
137 | /* Type specific error codes */ | 137 | /* Type specific error codes */ |
138 | IPSET_ERR_TYPE_SPECIFIC = 4352, | 138 | IPSET_ERR_TYPE_SPECIFIC = 4352, |
139 | }; | 139 | }; |
140 | 140 | ||
141 | /* Flags at command level */ | 141 | /* Flags at command level */ |
142 | enum ipset_cmd_flags { | 142 | enum ipset_cmd_flags { |
143 | IPSET_FLAG_BIT_EXIST = 0, | 143 | IPSET_FLAG_BIT_EXIST = 0, |
144 | IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST), | 144 | IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST), |
145 | IPSET_FLAG_BIT_LIST_SETNAME = 1, | ||
146 | IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME), | ||
147 | IPSET_FLAG_BIT_LIST_HEADER = 2, | ||
148 | IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER), | ||
145 | }; | 149 | }; |
146 | 150 | ||
147 | /* Flags at CADT attribute level */ | 151 | /* Flags at CADT attribute level */ |
148 | enum ipset_cadt_flags { | 152 | enum ipset_cadt_flags { |
149 | IPSET_FLAG_BIT_BEFORE = 0, | 153 | IPSET_FLAG_BIT_BEFORE = 0, |
150 | IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE), | 154 | IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE), |
151 | }; | 155 | }; |
152 | 156 | ||
153 | /* Commands with settype-specific attributes */ | 157 | /* Commands with settype-specific attributes */ |
154 | enum ipset_adt { | 158 | enum ipset_adt { |
155 | IPSET_ADD, | 159 | IPSET_ADD, |
156 | IPSET_DEL, | 160 | IPSET_DEL, |
157 | IPSET_TEST, | 161 | IPSET_TEST, |
158 | IPSET_ADT_MAX, | 162 | IPSET_ADT_MAX, |
159 | IPSET_CREATE = IPSET_ADT_MAX, | 163 | IPSET_CREATE = IPSET_ADT_MAX, |
160 | IPSET_CADT_MAX, | 164 | IPSET_CADT_MAX, |
161 | }; | 165 | }; |
162 | 166 | ||
163 | #ifdef __KERNEL__ | 167 | #ifdef __KERNEL__ |
164 | #include <linux/ip.h> | 168 | #include <linux/ip.h> |
165 | #include <linux/ipv6.h> | 169 | #include <linux/ipv6.h> |
166 | #include <linux/netlink.h> | 170 | #include <linux/netlink.h> |
167 | #include <linux/netfilter.h> | 171 | #include <linux/netfilter.h> |
168 | #include <linux/vmalloc.h> | 172 | #include <linux/vmalloc.h> |
169 | #include <net/netlink.h> | 173 | #include <net/netlink.h> |
170 | 174 | ||
171 | /* Sets are identified by an index in kernel space. Tweak with ip_set_id_t | 175 | /* Sets are identified by an index in kernel space. Tweak with ip_set_id_t |
172 | * and IPSET_INVALID_ID if you want to increase the max number of sets. | 176 | * and IPSET_INVALID_ID if you want to increase the max number of sets. |
173 | */ | 177 | */ |
174 | typedef u16 ip_set_id_t; | 178 | typedef u16 ip_set_id_t; |
175 | 179 | ||
176 | #define IPSET_INVALID_ID 65535 | 180 | #define IPSET_INVALID_ID 65535 |
177 | 181 | ||
178 | enum ip_set_dim { | 182 | enum ip_set_dim { |
179 | IPSET_DIM_ZERO = 0, | 183 | IPSET_DIM_ZERO = 0, |
180 | IPSET_DIM_ONE, | 184 | IPSET_DIM_ONE, |
181 | IPSET_DIM_TWO, | 185 | IPSET_DIM_TWO, |
182 | IPSET_DIM_THREE, | 186 | IPSET_DIM_THREE, |
183 | /* Max dimension in elements. | 187 | /* Max dimension in elements. |
184 | * If changed, new revision of iptables match/target is required. | 188 | * If changed, new revision of iptables match/target is required. |
185 | */ | 189 | */ |
186 | IPSET_DIM_MAX = 6, | 190 | IPSET_DIM_MAX = 6, |
187 | }; | 191 | }; |
188 | 192 | ||
189 | /* Option flags for kernel operations */ | 193 | /* Option flags for kernel operations */ |
190 | enum ip_set_kopt { | 194 | enum ip_set_kopt { |
191 | IPSET_INV_MATCH = (1 << IPSET_DIM_ZERO), | 195 | IPSET_INV_MATCH = (1 << IPSET_DIM_ZERO), |
192 | IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE), | 196 | IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE), |
193 | IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO), | 197 | IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO), |
194 | IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE), | 198 | IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE), |
195 | }; | 199 | }; |
196 | 200 | ||
197 | /* Set features */ | 201 | /* Set features */ |
198 | enum ip_set_feature { | 202 | enum ip_set_feature { |
199 | IPSET_TYPE_IP_FLAG = 0, | 203 | IPSET_TYPE_IP_FLAG = 0, |
200 | IPSET_TYPE_IP = (1 << IPSET_TYPE_IP_FLAG), | 204 | IPSET_TYPE_IP = (1 << IPSET_TYPE_IP_FLAG), |
201 | IPSET_TYPE_PORT_FLAG = 1, | 205 | IPSET_TYPE_PORT_FLAG = 1, |
202 | IPSET_TYPE_PORT = (1 << IPSET_TYPE_PORT_FLAG), | 206 | IPSET_TYPE_PORT = (1 << IPSET_TYPE_PORT_FLAG), |
203 | IPSET_TYPE_MAC_FLAG = 2, | 207 | IPSET_TYPE_MAC_FLAG = 2, |
204 | IPSET_TYPE_MAC = (1 << IPSET_TYPE_MAC_FLAG), | 208 | IPSET_TYPE_MAC = (1 << IPSET_TYPE_MAC_FLAG), |
205 | IPSET_TYPE_IP2_FLAG = 3, | 209 | IPSET_TYPE_IP2_FLAG = 3, |
206 | IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG), | 210 | IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG), |
207 | IPSET_TYPE_NAME_FLAG = 4, | 211 | IPSET_TYPE_NAME_FLAG = 4, |
208 | IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), | 212 | IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), |
209 | /* Strictly speaking not a feature, but a flag for dumping: | 213 | /* Strictly speaking not a feature, but a flag for dumping: |
210 | * this settype must be dumped last */ | 214 | * this settype must be dumped last */ |
211 | IPSET_DUMP_LAST_FLAG = 7, | 215 | IPSET_DUMP_LAST_FLAG = 7, |
212 | IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG), | 216 | IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG), |
213 | }; | 217 | }; |
214 | 218 | ||
215 | struct ip_set; | 219 | struct ip_set; |
216 | 220 | ||
217 | typedef int (*ipset_adtfn)(struct ip_set *set, void *value, | 221 | typedef int (*ipset_adtfn)(struct ip_set *set, void *value, |
218 | u32 timeout, u32 flags); | 222 | u32 timeout, u32 flags); |
219 | 223 | ||
220 | /* Kernel API function options */ | 224 | /* Kernel API function options */ |
221 | struct ip_set_adt_opt { | 225 | struct ip_set_adt_opt { |
222 | u8 family; /* Actual protocol family */ | 226 | u8 family; /* Actual protocol family */ |
223 | u8 dim; /* Dimension of match/target */ | 227 | u8 dim; /* Dimension of match/target */ |
224 | u8 flags; /* Direction and negation flags */ | 228 | u8 flags; /* Direction and negation flags */ |
225 | u32 cmdflags; /* Command-like flags */ | 229 | u32 cmdflags; /* Command-like flags */ |
226 | u32 timeout; /* Timeout value */ | 230 | u32 timeout; /* Timeout value */ |
227 | }; | 231 | }; |
228 | 232 | ||
229 | /* Set type, variant-specific part */ | 233 | /* Set type, variant-specific part */ |
230 | struct ip_set_type_variant { | 234 | struct ip_set_type_variant { |
231 | /* Kernelspace: test/add/del entries | 235 | /* Kernelspace: test/add/del entries |
232 | * returns negative error code, | 236 | * returns negative error code, |
233 | * zero for no match/success to add/delete | 237 | * zero for no match/success to add/delete |
234 | * positive for matching element */ | 238 | * positive for matching element */ |
235 | int (*kadt)(struct ip_set *set, const struct sk_buff * skb, | 239 | int (*kadt)(struct ip_set *set, const struct sk_buff * skb, |
236 | enum ipset_adt adt, const struct ip_set_adt_opt *opt); | 240 | enum ipset_adt adt, const struct ip_set_adt_opt *opt); |
237 | 241 | ||
238 | /* Userspace: test/add/del entries | 242 | /* Userspace: test/add/del entries |
239 | * returns negative error code, | 243 | * returns negative error code, |
240 | * zero for no match/success to add/delete | 244 | * zero for no match/success to add/delete |
241 | * positive for matching element */ | 245 | * positive for matching element */ |
242 | int (*uadt)(struct ip_set *set, struct nlattr *tb[], | 246 | int (*uadt)(struct ip_set *set, struct nlattr *tb[], |
243 | enum ipset_adt adt, u32 *lineno, u32 flags); | 247 | enum ipset_adt adt, u32 *lineno, u32 flags); |
244 | 248 | ||
245 | /* Low level add/del/test functions */ | 249 | /* Low level add/del/test functions */ |
246 | ipset_adtfn adt[IPSET_ADT_MAX]; | 250 | ipset_adtfn adt[IPSET_ADT_MAX]; |
247 | 251 | ||
248 | /* When adding entries and set is full, try to resize the set */ | 252 | /* When adding entries and set is full, try to resize the set */ |
249 | int (*resize)(struct ip_set *set, bool retried); | 253 | int (*resize)(struct ip_set *set, bool retried); |
250 | /* Destroy the set */ | 254 | /* Destroy the set */ |
251 | void (*destroy)(struct ip_set *set); | 255 | void (*destroy)(struct ip_set *set); |
252 | /* Flush the elements */ | 256 | /* Flush the elements */ |
253 | void (*flush)(struct ip_set *set); | 257 | void (*flush)(struct ip_set *set); |
254 | /* Expire entries before listing */ | 258 | /* Expire entries before listing */ |
255 | void (*expire)(struct ip_set *set); | 259 | void (*expire)(struct ip_set *set); |
256 | /* List set header data */ | 260 | /* List set header data */ |
257 | int (*head)(struct ip_set *set, struct sk_buff *skb); | 261 | int (*head)(struct ip_set *set, struct sk_buff *skb); |
258 | /* List elements */ | 262 | /* List elements */ |
259 | int (*list)(const struct ip_set *set, struct sk_buff *skb, | 263 | int (*list)(const struct ip_set *set, struct sk_buff *skb, |
260 | struct netlink_callback *cb); | 264 | struct netlink_callback *cb); |
261 | 265 | ||
262 | /* Return true if "b" set is the same as "a" | 266 | /* Return true if "b" set is the same as "a" |
263 | * according to the create set parameters */ | 267 | * according to the create set parameters */ |
264 | bool (*same_set)(const struct ip_set *a, const struct ip_set *b); | 268 | bool (*same_set)(const struct ip_set *a, const struct ip_set *b); |
265 | }; | 269 | }; |
266 | 270 | ||
267 | /* The core set type structure */ | 271 | /* The core set type structure */ |
268 | struct ip_set_type { | 272 | struct ip_set_type { |
269 | struct list_head list; | 273 | struct list_head list; |
270 | 274 | ||
271 | /* Typename */ | 275 | /* Typename */ |
272 | char name[IPSET_MAXNAMELEN]; | 276 | char name[IPSET_MAXNAMELEN]; |
273 | /* Protocol version */ | 277 | /* Protocol version */ |
274 | u8 protocol; | 278 | u8 protocol; |
275 | /* Set features to control swapping */ | 279 | /* Set features to control swapping */ |
276 | u8 features; | 280 | u8 features; |
277 | /* Set type dimension */ | 281 | /* Set type dimension */ |
278 | u8 dimension; | 282 | u8 dimension; |
279 | /* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */ | 283 | /* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */ |
280 | u8 family; | 284 | u8 family; |
281 | /* Type revision */ | 285 | /* Type revision */ |
282 | u8 revision; | 286 | u8 revision; |
283 | 287 | ||
284 | /* Create set */ | 288 | /* Create set */ |
285 | int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags); | 289 | int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags); |
286 | 290 | ||
287 | /* Attribute policies */ | 291 | /* Attribute policies */ |
288 | const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1]; | 292 | const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1]; |
289 | const struct nla_policy adt_policy[IPSET_ATTR_ADT_MAX + 1]; | 293 | const struct nla_policy adt_policy[IPSET_ATTR_ADT_MAX + 1]; |
290 | 294 | ||
291 | /* Set this to THIS_MODULE if you are a module, otherwise NULL */ | 295 | /* Set this to THIS_MODULE if you are a module, otherwise NULL */ |
292 | struct module *me; | 296 | struct module *me; |
293 | }; | 297 | }; |
294 | 298 | ||
295 | /* register and unregister set type */ | 299 | /* register and unregister set type */ |
296 | extern int ip_set_type_register(struct ip_set_type *set_type); | 300 | extern int ip_set_type_register(struct ip_set_type *set_type); |
297 | extern void ip_set_type_unregister(struct ip_set_type *set_type); | 301 | extern void ip_set_type_unregister(struct ip_set_type *set_type); |
298 | 302 | ||
299 | /* A generic IP set */ | 303 | /* A generic IP set */ |
300 | struct ip_set { | 304 | struct ip_set { |
301 | /* The name of the set */ | 305 | /* The name of the set */ |
302 | char name[IPSET_MAXNAMELEN]; | 306 | char name[IPSET_MAXNAMELEN]; |
303 | /* Lock protecting the set data */ | 307 | /* Lock protecting the set data */ |
304 | rwlock_t lock; | 308 | rwlock_t lock; |
305 | /* References to the set */ | 309 | /* References to the set */ |
306 | u32 ref; | 310 | u32 ref; |
307 | /* The core set type */ | 311 | /* The core set type */ |
308 | struct ip_set_type *type; | 312 | struct ip_set_type *type; |
309 | /* The type variant doing the real job */ | 313 | /* The type variant doing the real job */ |
310 | const struct ip_set_type_variant *variant; | 314 | const struct ip_set_type_variant *variant; |
311 | /* The actual INET family of the set */ | 315 | /* The actual INET family of the set */ |
312 | u8 family; | 316 | u8 family; |
313 | /* The type specific data */ | 317 | /* The type specific data */ |
314 | void *data; | 318 | void *data; |
315 | }; | 319 | }; |
316 | 320 | ||
317 | /* register and unregister set references */ | 321 | /* register and unregister set references */ |
318 | extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set); | 322 | extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set); |
319 | extern void ip_set_put_byindex(ip_set_id_t index); | 323 | extern void ip_set_put_byindex(ip_set_id_t index); |
320 | extern const char * ip_set_name_byindex(ip_set_id_t index); | 324 | extern const char * ip_set_name_byindex(ip_set_id_t index); |
321 | extern ip_set_id_t ip_set_nfnl_get(const char *name); | 325 | extern ip_set_id_t ip_set_nfnl_get(const char *name); |
322 | extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index); | 326 | extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index); |
323 | extern void ip_set_nfnl_put(ip_set_id_t index); | 327 | extern void ip_set_nfnl_put(ip_set_id_t index); |
324 | 328 | ||
325 | /* API for iptables set match, and SET target */ | 329 | /* API for iptables set match, and SET target */ |
326 | 330 | ||
327 | extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb, | 331 | extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb, |
328 | const struct ip_set_adt_opt *opt); | 332 | const struct ip_set_adt_opt *opt); |
329 | extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb, | 333 | extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb, |
330 | const struct ip_set_adt_opt *opt); | 334 | const struct ip_set_adt_opt *opt); |
331 | extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb, | 335 | extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb, |
332 | const struct ip_set_adt_opt *opt); | 336 | const struct ip_set_adt_opt *opt); |
333 | 337 | ||
334 | /* Utility functions */ | 338 | /* Utility functions */ |
335 | extern void * ip_set_alloc(size_t size); | 339 | extern void * ip_set_alloc(size_t size); |
336 | extern void ip_set_free(void *members); | 340 | extern void ip_set_free(void *members); |
337 | extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); | 341 | extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); |
338 | extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr); | 342 | extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr); |
339 | 343 | ||
340 | static inline int | 344 | static inline int |
341 | ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr) | 345 | ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr) |
342 | { | 346 | { |
343 | __be32 ip; | 347 | __be32 ip; |
344 | int ret = ip_set_get_ipaddr4(nla, &ip); | 348 | int ret = ip_set_get_ipaddr4(nla, &ip); |
345 | 349 | ||
346 | if (ret) | 350 | if (ret) |
347 | return ret; | 351 | return ret; |
348 | *ipaddr = ntohl(ip); | 352 | *ipaddr = ntohl(ip); |
349 | return 0; | 353 | return 0; |
350 | } | 354 | } |
351 | 355 | ||
352 | /* Ignore IPSET_ERR_EXIST errors if asked to do so? */ | 356 | /* Ignore IPSET_ERR_EXIST errors if asked to do so? */ |
353 | static inline bool | 357 | static inline bool |
354 | ip_set_eexist(int ret, u32 flags) | 358 | ip_set_eexist(int ret, u32 flags) |
355 | { | 359 | { |
356 | return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST); | 360 | return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST); |
357 | } | 361 | } |
358 | 362 | ||
359 | /* Check the NLA_F_NET_BYTEORDER flag */ | 363 | /* Check the NLA_F_NET_BYTEORDER flag */ |
360 | static inline bool | 364 | static inline bool |
361 | ip_set_attr_netorder(struct nlattr *tb[], int type) | 365 | ip_set_attr_netorder(struct nlattr *tb[], int type) |
362 | { | 366 | { |
363 | return tb[type] && (tb[type]->nla_type & NLA_F_NET_BYTEORDER); | 367 | return tb[type] && (tb[type]->nla_type & NLA_F_NET_BYTEORDER); |
364 | } | 368 | } |
365 | 369 | ||
366 | static inline bool | 370 | static inline bool |
367 | ip_set_optattr_netorder(struct nlattr *tb[], int type) | 371 | ip_set_optattr_netorder(struct nlattr *tb[], int type) |
368 | { | 372 | { |
369 | return !tb[type] || (tb[type]->nla_type & NLA_F_NET_BYTEORDER); | 373 | return !tb[type] || (tb[type]->nla_type & NLA_F_NET_BYTEORDER); |
370 | } | 374 | } |
371 | 375 | ||
372 | /* Useful converters */ | 376 | /* Useful converters */ |
373 | static inline u32 | 377 | static inline u32 |
374 | ip_set_get_h32(const struct nlattr *attr) | 378 | ip_set_get_h32(const struct nlattr *attr) |
375 | { | 379 | { |
376 | return ntohl(nla_get_be32(attr)); | 380 | return ntohl(nla_get_be32(attr)); |
377 | } | 381 | } |
378 | 382 | ||
379 | static inline u16 | 383 | static inline u16 |
380 | ip_set_get_h16(const struct nlattr *attr) | 384 | ip_set_get_h16(const struct nlattr *attr) |
381 | { | 385 | { |
382 | return ntohs(nla_get_be16(attr)); | 386 | return ntohs(nla_get_be16(attr)); |
383 | } | 387 | } |
384 | 388 | ||
385 | #define ipset_nest_start(skb, attr) nla_nest_start(skb, attr | NLA_F_NESTED) | 389 | #define ipset_nest_start(skb, attr) nla_nest_start(skb, attr | NLA_F_NESTED) |
386 | #define ipset_nest_end(skb, start) nla_nest_end(skb, start) | 390 | #define ipset_nest_end(skb, start) nla_nest_end(skb, start) |
387 | 391 | ||
388 | #define NLA_PUT_IPADDR4(skb, type, ipaddr) \ | 392 | #define NLA_PUT_IPADDR4(skb, type, ipaddr) \ |
389 | do { \ | 393 | do { \ |
390 | struct nlattr *__nested = ipset_nest_start(skb, type); \ | 394 | struct nlattr *__nested = ipset_nest_start(skb, type); \ |
391 | \ | 395 | \ |
392 | if (!__nested) \ | 396 | if (!__nested) \ |
393 | goto nla_put_failure; \ | 397 | goto nla_put_failure; \ |
394 | NLA_PUT_NET32(skb, IPSET_ATTR_IPADDR_IPV4, ipaddr); \ | 398 | NLA_PUT_NET32(skb, IPSET_ATTR_IPADDR_IPV4, ipaddr); \ |
395 | ipset_nest_end(skb, __nested); \ | 399 | ipset_nest_end(skb, __nested); \ |
396 | } while (0) | 400 | } while (0) |
397 | 401 | ||
398 | #define NLA_PUT_IPADDR6(skb, type, ipaddrptr) \ | 402 | #define NLA_PUT_IPADDR6(skb, type, ipaddrptr) \ |
399 | do { \ | 403 | do { \ |
400 | struct nlattr *__nested = ipset_nest_start(skb, type); \ | 404 | struct nlattr *__nested = ipset_nest_start(skb, type); \ |
401 | \ | 405 | \ |
402 | if (!__nested) \ | 406 | if (!__nested) \ |
403 | goto nla_put_failure; \ | 407 | goto nla_put_failure; \ |
404 | NLA_PUT(skb, IPSET_ATTR_IPADDR_IPV6, \ | 408 | NLA_PUT(skb, IPSET_ATTR_IPADDR_IPV6, \ |
405 | sizeof(struct in6_addr), ipaddrptr); \ | 409 | sizeof(struct in6_addr), ipaddrptr); \ |
406 | ipset_nest_end(skb, __nested); \ | 410 | ipset_nest_end(skb, __nested); \ |
407 | } while (0) | 411 | } while (0) |
408 | 412 | ||
409 | /* Get address from skbuff */ | 413 | /* Get address from skbuff */ |
410 | static inline __be32 | 414 | static inline __be32 |
411 | ip4addr(const struct sk_buff *skb, bool src) | 415 | ip4addr(const struct sk_buff *skb, bool src) |
412 | { | 416 | { |
413 | return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; | 417 | return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; |
414 | } | 418 | } |
415 | 419 | ||
416 | static inline void | 420 | static inline void |
417 | ip4addrptr(const struct sk_buff *skb, bool src, __be32 *addr) | 421 | ip4addrptr(const struct sk_buff *skb, bool src, __be32 *addr) |
418 | { | 422 | { |
419 | *addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; | 423 | *addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; |
420 | } | 424 | } |
421 | 425 | ||
422 | static inline void | 426 | static inline void |
423 | ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr) | 427 | ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr) |
424 | { | 428 | { |
425 | memcpy(addr, src ? &ipv6_hdr(skb)->saddr : &ipv6_hdr(skb)->daddr, | 429 | memcpy(addr, src ? &ipv6_hdr(skb)->saddr : &ipv6_hdr(skb)->daddr, |
426 | sizeof(*addr)); | 430 | sizeof(*addr)); |
427 | } | 431 | } |
428 | 432 | ||
429 | /* Calculate the bytes required to store the inclusive range of a-b */ | 433 | /* Calculate the bytes required to store the inclusive range of a-b */ |
430 | static inline int | 434 | static inline int |
431 | bitmap_bytes(u32 a, u32 b) | 435 | bitmap_bytes(u32 a, u32 b) |
432 | { | 436 | { |
433 | return 4 * ((((b - a + 8) / 8) + 3) / 4); | 437 | return 4 * ((((b - a + 8) / 8) + 3) / 4); |
434 | } | 438 | } |
435 | 439 | ||
436 | /* Interface to iptables/ip6tables */ | 440 | /* Interface to iptables/ip6tables */ |
437 | 441 | ||
438 | #define SO_IP_SET 83 | 442 | #define SO_IP_SET 83 |
439 | 443 | ||
440 | union ip_set_name_index { | 444 | union ip_set_name_index { |
441 | char name[IPSET_MAXNAMELEN]; | 445 | char name[IPSET_MAXNAMELEN]; |
442 | ip_set_id_t index; | 446 | ip_set_id_t index; |
443 | }; | 447 | }; |
444 | 448 | ||
445 | #define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */ | 449 | #define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */ |
446 | struct ip_set_req_get_set { | 450 | struct ip_set_req_get_set { |
447 | unsigned op; | 451 | unsigned op; |
448 | unsigned version; | 452 | unsigned version; |
449 | union ip_set_name_index set; | 453 | union ip_set_name_index set; |
450 | }; | 454 | }; |
451 | 455 | ||
452 | #define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */ | 456 | #define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */ |
453 | /* Uses ip_set_req_get_set */ | 457 | /* Uses ip_set_req_get_set */ |
454 | 458 | ||
455 | #define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ | 459 | #define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ |
456 | struct ip_set_req_version { | 460 | struct ip_set_req_version { |
457 | unsigned op; | 461 | unsigned op; |
458 | unsigned version; | 462 | unsigned version; |
459 | }; | 463 | }; |
460 | 464 | ||
461 | #endif /* __KERNEL__ */ | 465 | #endif /* __KERNEL__ */ |
462 | 466 | ||
463 | #endif /*_IP_SET_H */ | 467 | #endif /*_IP_SET_H */ |
464 | 468 |
net/netfilter/ipset/ip_set_core.c
1 | /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> | 1 | /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> |
2 | * Patrick Schaaf <bof@bof.de> | 2 | * Patrick Schaaf <bof@bof.de> |
3 | * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 3 | * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | /* Kernel module for IP set management */ | 10 | /* Kernel module for IP set management */ |
11 | 11 | ||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/moduleparam.h> | 14 | #include <linux/moduleparam.h> |
15 | #include <linux/ip.h> | 15 | #include <linux/ip.h> |
16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
18 | #include <linux/netlink.h> | 18 | #include <linux/netlink.h> |
19 | #include <linux/rculist.h> | 19 | #include <linux/rculist.h> |
20 | #include <linux/version.h> | 20 | #include <linux/version.h> |
21 | #include <net/netlink.h> | 21 | #include <net/netlink.h> |
22 | 22 | ||
23 | #include <linux/netfilter.h> | 23 | #include <linux/netfilter.h> |
24 | #include <linux/netfilter/nfnetlink.h> | 24 | #include <linux/netfilter/nfnetlink.h> |
25 | #include <linux/netfilter/ipset/ip_set.h> | 25 | #include <linux/netfilter/ipset/ip_set.h> |
26 | 26 | ||
27 | static LIST_HEAD(ip_set_type_list); /* all registered set types */ | 27 | static LIST_HEAD(ip_set_type_list); /* all registered set types */ |
28 | static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ | 28 | static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ |
29 | static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */ | 29 | static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */ |
30 | 30 | ||
31 | static struct ip_set **ip_set_list; /* all individual sets */ | 31 | static struct ip_set **ip_set_list; /* all individual sets */ |
32 | static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */ | 32 | static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */ |
33 | 33 | ||
34 | #define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0) | 34 | #define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0) |
35 | 35 | ||
36 | static unsigned int max_sets; | 36 | static unsigned int max_sets; |
37 | 37 | ||
38 | module_param(max_sets, int, 0600); | 38 | module_param(max_sets, int, 0600); |
39 | MODULE_PARM_DESC(max_sets, "maximal number of sets"); | 39 | MODULE_PARM_DESC(max_sets, "maximal number of sets"); |
40 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
41 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 41 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
42 | MODULE_DESCRIPTION("core IP set support"); | 42 | MODULE_DESCRIPTION("core IP set support"); |
43 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET); | 43 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET); |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * The set types are implemented in modules and registered set types | 46 | * The set types are implemented in modules and registered set types |
47 | * can be found in ip_set_type_list. Adding/deleting types is | 47 | * can be found in ip_set_type_list. Adding/deleting types is |
48 | * serialized by ip_set_type_mutex. | 48 | * serialized by ip_set_type_mutex. |
49 | */ | 49 | */ |
50 | 50 | ||
51 | static inline void | 51 | static inline void |
52 | ip_set_type_lock(void) | 52 | ip_set_type_lock(void) |
53 | { | 53 | { |
54 | mutex_lock(&ip_set_type_mutex); | 54 | mutex_lock(&ip_set_type_mutex); |
55 | } | 55 | } |
56 | 56 | ||
57 | static inline void | 57 | static inline void |
58 | ip_set_type_unlock(void) | 58 | ip_set_type_unlock(void) |
59 | { | 59 | { |
60 | mutex_unlock(&ip_set_type_mutex); | 60 | mutex_unlock(&ip_set_type_mutex); |
61 | } | 61 | } |
62 | 62 | ||
63 | /* Register and deregister settype */ | 63 | /* Register and deregister settype */ |
64 | 64 | ||
65 | static struct ip_set_type * | 65 | static struct ip_set_type * |
66 | find_set_type(const char *name, u8 family, u8 revision) | 66 | find_set_type(const char *name, u8 family, u8 revision) |
67 | { | 67 | { |
68 | struct ip_set_type *type; | 68 | struct ip_set_type *type; |
69 | 69 | ||
70 | list_for_each_entry_rcu(type, &ip_set_type_list, list) | 70 | list_for_each_entry_rcu(type, &ip_set_type_list, list) |
71 | if (STREQ(type->name, name) && | 71 | if (STREQ(type->name, name) && |
72 | (type->family == family || type->family == AF_UNSPEC) && | 72 | (type->family == family || type->family == AF_UNSPEC) && |
73 | type->revision == revision) | 73 | type->revision == revision) |
74 | return type; | 74 | return type; |
75 | return NULL; | 75 | return NULL; |
76 | } | 76 | } |
77 | 77 | ||
78 | /* Unlock, try to load a set type module and lock again */ | 78 | /* Unlock, try to load a set type module and lock again */ |
79 | static int | 79 | static int |
80 | try_to_load_type(const char *name) | 80 | try_to_load_type(const char *name) |
81 | { | 81 | { |
82 | nfnl_unlock(); | 82 | nfnl_unlock(); |
83 | pr_debug("try to load ip_set_%s\n", name); | 83 | pr_debug("try to load ip_set_%s\n", name); |
84 | if (request_module("ip_set_%s", name) < 0) { | 84 | if (request_module("ip_set_%s", name) < 0) { |
85 | pr_warning("Can't find ip_set type %s\n", name); | 85 | pr_warning("Can't find ip_set type %s\n", name); |
86 | nfnl_lock(); | 86 | nfnl_lock(); |
87 | return -IPSET_ERR_FIND_TYPE; | 87 | return -IPSET_ERR_FIND_TYPE; |
88 | } | 88 | } |
89 | nfnl_lock(); | 89 | nfnl_lock(); |
90 | return -EAGAIN; | 90 | return -EAGAIN; |
91 | } | 91 | } |
92 | 92 | ||
93 | /* Find a set type and reference it */ | 93 | /* Find a set type and reference it */ |
94 | static int | 94 | static int |
95 | find_set_type_get(const char *name, u8 family, u8 revision, | 95 | find_set_type_get(const char *name, u8 family, u8 revision, |
96 | struct ip_set_type **found) | 96 | struct ip_set_type **found) |
97 | { | 97 | { |
98 | struct ip_set_type *type; | 98 | struct ip_set_type *type; |
99 | int err; | 99 | int err; |
100 | 100 | ||
101 | rcu_read_lock(); | 101 | rcu_read_lock(); |
102 | *found = find_set_type(name, family, revision); | 102 | *found = find_set_type(name, family, revision); |
103 | if (*found) { | 103 | if (*found) { |
104 | err = !try_module_get((*found)->me) ? -EFAULT : 0; | 104 | err = !try_module_get((*found)->me) ? -EFAULT : 0; |
105 | goto unlock; | 105 | goto unlock; |
106 | } | 106 | } |
107 | /* Make sure the type is loaded but we don't support the revision */ | 107 | /* Make sure the type is loaded but we don't support the revision */ |
108 | list_for_each_entry_rcu(type, &ip_set_type_list, list) | 108 | list_for_each_entry_rcu(type, &ip_set_type_list, list) |
109 | if (STREQ(type->name, name)) { | 109 | if (STREQ(type->name, name)) { |
110 | err = -IPSET_ERR_FIND_TYPE; | 110 | err = -IPSET_ERR_FIND_TYPE; |
111 | goto unlock; | 111 | goto unlock; |
112 | } | 112 | } |
113 | rcu_read_unlock(); | 113 | rcu_read_unlock(); |
114 | 114 | ||
115 | return try_to_load_type(name); | 115 | return try_to_load_type(name); |
116 | 116 | ||
117 | unlock: | 117 | unlock: |
118 | rcu_read_unlock(); | 118 | rcu_read_unlock(); |
119 | return err; | 119 | return err; |
120 | } | 120 | } |
121 | 121 | ||
122 | /* Find a given set type by name and family. | 122 | /* Find a given set type by name and family. |
123 | * If we succeeded, the supported minimal and maximum revisions are | 123 | * If we succeeded, the supported minimal and maximum revisions are |
124 | * filled out. | 124 | * filled out. |
125 | */ | 125 | */ |
126 | static int | 126 | static int |
127 | find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max) | 127 | find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max) |
128 | { | 128 | { |
129 | struct ip_set_type *type; | 129 | struct ip_set_type *type; |
130 | bool found = false; | 130 | bool found = false; |
131 | 131 | ||
132 | *min = 255; *max = 0; | 132 | *min = 255; *max = 0; |
133 | rcu_read_lock(); | 133 | rcu_read_lock(); |
134 | list_for_each_entry_rcu(type, &ip_set_type_list, list) | 134 | list_for_each_entry_rcu(type, &ip_set_type_list, list) |
135 | if (STREQ(type->name, name) && | 135 | if (STREQ(type->name, name) && |
136 | (type->family == family || type->family == AF_UNSPEC)) { | 136 | (type->family == family || type->family == AF_UNSPEC)) { |
137 | found = true; | 137 | found = true; |
138 | if (type->revision < *min) | 138 | if (type->revision < *min) |
139 | *min = type->revision; | 139 | *min = type->revision; |
140 | if (type->revision > *max) | 140 | if (type->revision > *max) |
141 | *max = type->revision; | 141 | *max = type->revision; |
142 | } | 142 | } |
143 | rcu_read_unlock(); | 143 | rcu_read_unlock(); |
144 | if (found) | 144 | if (found) |
145 | return 0; | 145 | return 0; |
146 | 146 | ||
147 | return try_to_load_type(name); | 147 | return try_to_load_type(name); |
148 | } | 148 | } |
149 | 149 | ||
150 | #define family_name(f) ((f) == AF_INET ? "inet" : \ | 150 | #define family_name(f) ((f) == AF_INET ? "inet" : \ |
151 | (f) == AF_INET6 ? "inet6" : "any") | 151 | (f) == AF_INET6 ? "inet6" : "any") |
152 | 152 | ||
153 | /* Register a set type structure. The type is identified by | 153 | /* Register a set type structure. The type is identified by |
154 | * the unique triple of name, family and revision. | 154 | * the unique triple of name, family and revision. |
155 | */ | 155 | */ |
156 | int | 156 | int |
157 | ip_set_type_register(struct ip_set_type *type) | 157 | ip_set_type_register(struct ip_set_type *type) |
158 | { | 158 | { |
159 | int ret = 0; | 159 | int ret = 0; |
160 | 160 | ||
161 | if (type->protocol != IPSET_PROTOCOL) { | 161 | if (type->protocol != IPSET_PROTOCOL) { |
162 | pr_warning("ip_set type %s, family %s, revision %u uses " | 162 | pr_warning("ip_set type %s, family %s, revision %u uses " |
163 | "wrong protocol version %u (want %u)\n", | 163 | "wrong protocol version %u (want %u)\n", |
164 | type->name, family_name(type->family), | 164 | type->name, family_name(type->family), |
165 | type->revision, type->protocol, IPSET_PROTOCOL); | 165 | type->revision, type->protocol, IPSET_PROTOCOL); |
166 | return -EINVAL; | 166 | return -EINVAL; |
167 | } | 167 | } |
168 | 168 | ||
169 | ip_set_type_lock(); | 169 | ip_set_type_lock(); |
170 | if (find_set_type(type->name, type->family, type->revision)) { | 170 | if (find_set_type(type->name, type->family, type->revision)) { |
171 | /* Duplicate! */ | 171 | /* Duplicate! */ |
172 | pr_warning("ip_set type %s, family %s, revision %u " | 172 | pr_warning("ip_set type %s, family %s, revision %u " |
173 | "already registered!\n", type->name, | 173 | "already registered!\n", type->name, |
174 | family_name(type->family), type->revision); | 174 | family_name(type->family), type->revision); |
175 | ret = -EINVAL; | 175 | ret = -EINVAL; |
176 | goto unlock; | 176 | goto unlock; |
177 | } | 177 | } |
178 | list_add_rcu(&type->list, &ip_set_type_list); | 178 | list_add_rcu(&type->list, &ip_set_type_list); |
179 | pr_debug("type %s, family %s, revision %u registered.\n", | 179 | pr_debug("type %s, family %s, revision %u registered.\n", |
180 | type->name, family_name(type->family), type->revision); | 180 | type->name, family_name(type->family), type->revision); |
181 | unlock: | 181 | unlock: |
182 | ip_set_type_unlock(); | 182 | ip_set_type_unlock(); |
183 | return ret; | 183 | return ret; |
184 | } | 184 | } |
185 | EXPORT_SYMBOL_GPL(ip_set_type_register); | 185 | EXPORT_SYMBOL_GPL(ip_set_type_register); |
186 | 186 | ||
187 | /* Unregister a set type. There's a small race with ip_set_create */ | 187 | /* Unregister a set type. There's a small race with ip_set_create */ |
188 | void | 188 | void |
189 | ip_set_type_unregister(struct ip_set_type *type) | 189 | ip_set_type_unregister(struct ip_set_type *type) |
190 | { | 190 | { |
191 | ip_set_type_lock(); | 191 | ip_set_type_lock(); |
192 | if (!find_set_type(type->name, type->family, type->revision)) { | 192 | if (!find_set_type(type->name, type->family, type->revision)) { |
193 | pr_warning("ip_set type %s, family %s, revision %u " | 193 | pr_warning("ip_set type %s, family %s, revision %u " |
194 | "not registered\n", type->name, | 194 | "not registered\n", type->name, |
195 | family_name(type->family), type->revision); | 195 | family_name(type->family), type->revision); |
196 | goto unlock; | 196 | goto unlock; |
197 | } | 197 | } |
198 | list_del_rcu(&type->list); | 198 | list_del_rcu(&type->list); |
199 | pr_debug("type %s, family %s, revision %u unregistered.\n", | 199 | pr_debug("type %s, family %s, revision %u unregistered.\n", |
200 | type->name, family_name(type->family), type->revision); | 200 | type->name, family_name(type->family), type->revision); |
201 | unlock: | 201 | unlock: |
202 | ip_set_type_unlock(); | 202 | ip_set_type_unlock(); |
203 | 203 | ||
204 | synchronize_rcu(); | 204 | synchronize_rcu(); |
205 | } | 205 | } |
206 | EXPORT_SYMBOL_GPL(ip_set_type_unregister); | 206 | EXPORT_SYMBOL_GPL(ip_set_type_unregister); |
207 | 207 | ||
208 | /* Utility functions */ | 208 | /* Utility functions */ |
209 | void * | 209 | void * |
210 | ip_set_alloc(size_t size) | 210 | ip_set_alloc(size_t size) |
211 | { | 211 | { |
212 | void *members = NULL; | 212 | void *members = NULL; |
213 | 213 | ||
214 | if (size < KMALLOC_MAX_SIZE) | 214 | if (size < KMALLOC_MAX_SIZE) |
215 | members = kzalloc(size, GFP_KERNEL | __GFP_NOWARN); | 215 | members = kzalloc(size, GFP_KERNEL | __GFP_NOWARN); |
216 | 216 | ||
217 | if (members) { | 217 | if (members) { |
218 | pr_debug("%p: allocated with kmalloc\n", members); | 218 | pr_debug("%p: allocated with kmalloc\n", members); |
219 | return members; | 219 | return members; |
220 | } | 220 | } |
221 | 221 | ||
222 | members = vzalloc(size); | 222 | members = vzalloc(size); |
223 | if (!members) | 223 | if (!members) |
224 | return NULL; | 224 | return NULL; |
225 | pr_debug("%p: allocated with vmalloc\n", members); | 225 | pr_debug("%p: allocated with vmalloc\n", members); |
226 | 226 | ||
227 | return members; | 227 | return members; |
228 | } | 228 | } |
229 | EXPORT_SYMBOL_GPL(ip_set_alloc); | 229 | EXPORT_SYMBOL_GPL(ip_set_alloc); |
230 | 230 | ||
231 | void | 231 | void |
232 | ip_set_free(void *members) | 232 | ip_set_free(void *members) |
233 | { | 233 | { |
234 | pr_debug("%p: free with %s\n", members, | 234 | pr_debug("%p: free with %s\n", members, |
235 | is_vmalloc_addr(members) ? "vfree" : "kfree"); | 235 | is_vmalloc_addr(members) ? "vfree" : "kfree"); |
236 | if (is_vmalloc_addr(members)) | 236 | if (is_vmalloc_addr(members)) |
237 | vfree(members); | 237 | vfree(members); |
238 | else | 238 | else |
239 | kfree(members); | 239 | kfree(members); |
240 | } | 240 | } |
241 | EXPORT_SYMBOL_GPL(ip_set_free); | 241 | EXPORT_SYMBOL_GPL(ip_set_free); |
242 | 242 | ||
243 | static inline bool | 243 | static inline bool |
244 | flag_nested(const struct nlattr *nla) | 244 | flag_nested(const struct nlattr *nla) |
245 | { | 245 | { |
246 | return nla->nla_type & NLA_F_NESTED; | 246 | return nla->nla_type & NLA_F_NESTED; |
247 | } | 247 | } |
248 | 248 | ||
249 | static const struct nla_policy ipaddr_policy[IPSET_ATTR_IPADDR_MAX + 1] = { | 249 | static const struct nla_policy ipaddr_policy[IPSET_ATTR_IPADDR_MAX + 1] = { |
250 | [IPSET_ATTR_IPADDR_IPV4] = { .type = NLA_U32 }, | 250 | [IPSET_ATTR_IPADDR_IPV4] = { .type = NLA_U32 }, |
251 | [IPSET_ATTR_IPADDR_IPV6] = { .type = NLA_BINARY, | 251 | [IPSET_ATTR_IPADDR_IPV6] = { .type = NLA_BINARY, |
252 | .len = sizeof(struct in6_addr) }, | 252 | .len = sizeof(struct in6_addr) }, |
253 | }; | 253 | }; |
254 | 254 | ||
255 | int | 255 | int |
256 | ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr) | 256 | ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr) |
257 | { | 257 | { |
258 | struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1]; | 258 | struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1]; |
259 | 259 | ||
260 | if (unlikely(!flag_nested(nla))) | 260 | if (unlikely(!flag_nested(nla))) |
261 | return -IPSET_ERR_PROTOCOL; | 261 | return -IPSET_ERR_PROTOCOL; |
262 | if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy)) | 262 | if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy)) |
263 | return -IPSET_ERR_PROTOCOL; | 263 | return -IPSET_ERR_PROTOCOL; |
264 | if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV4))) | 264 | if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV4))) |
265 | return -IPSET_ERR_PROTOCOL; | 265 | return -IPSET_ERR_PROTOCOL; |
266 | 266 | ||
267 | *ipaddr = nla_get_be32(tb[IPSET_ATTR_IPADDR_IPV4]); | 267 | *ipaddr = nla_get_be32(tb[IPSET_ATTR_IPADDR_IPV4]); |
268 | return 0; | 268 | return 0; |
269 | } | 269 | } |
270 | EXPORT_SYMBOL_GPL(ip_set_get_ipaddr4); | 270 | EXPORT_SYMBOL_GPL(ip_set_get_ipaddr4); |
271 | 271 | ||
272 | int | 272 | int |
273 | ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr) | 273 | ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr) |
274 | { | 274 | { |
275 | struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1]; | 275 | struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1]; |
276 | 276 | ||
277 | if (unlikely(!flag_nested(nla))) | 277 | if (unlikely(!flag_nested(nla))) |
278 | return -IPSET_ERR_PROTOCOL; | 278 | return -IPSET_ERR_PROTOCOL; |
279 | 279 | ||
280 | if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy)) | 280 | if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy)) |
281 | return -IPSET_ERR_PROTOCOL; | 281 | return -IPSET_ERR_PROTOCOL; |
282 | if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV6))) | 282 | if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV6))) |
283 | return -IPSET_ERR_PROTOCOL; | 283 | return -IPSET_ERR_PROTOCOL; |
284 | 284 | ||
285 | memcpy(ipaddr, nla_data(tb[IPSET_ATTR_IPADDR_IPV6]), | 285 | memcpy(ipaddr, nla_data(tb[IPSET_ATTR_IPADDR_IPV6]), |
286 | sizeof(struct in6_addr)); | 286 | sizeof(struct in6_addr)); |
287 | return 0; | 287 | return 0; |
288 | } | 288 | } |
289 | EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6); | 289 | EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6); |
290 | 290 | ||
291 | /* | 291 | /* |
292 | * Creating/destroying/renaming/swapping affect the existence and | 292 | * Creating/destroying/renaming/swapping affect the existence and |
293 | * the properties of a set. All of these can be executed from userspace | 293 | * the properties of a set. All of these can be executed from userspace |
294 | * only and serialized by the nfnl mutex indirectly from nfnetlink. | 294 | * only and serialized by the nfnl mutex indirectly from nfnetlink. |
295 | * | 295 | * |
296 | * Sets are identified by their index in ip_set_list and the index | 296 | * Sets are identified by their index in ip_set_list and the index |
297 | * is used by the external references (set/SET netfilter modules). | 297 | * is used by the external references (set/SET netfilter modules). |
298 | * | 298 | * |
299 | * The set behind an index may change by swapping only, from userspace. | 299 | * The set behind an index may change by swapping only, from userspace. |
300 | */ | 300 | */ |
301 | 301 | ||
302 | static inline void | 302 | static inline void |
303 | __ip_set_get(ip_set_id_t index) | 303 | __ip_set_get(ip_set_id_t index) |
304 | { | 304 | { |
305 | write_lock_bh(&ip_set_ref_lock); | 305 | write_lock_bh(&ip_set_ref_lock); |
306 | ip_set_list[index]->ref++; | 306 | ip_set_list[index]->ref++; |
307 | write_unlock_bh(&ip_set_ref_lock); | 307 | write_unlock_bh(&ip_set_ref_lock); |
308 | } | 308 | } |
309 | 309 | ||
310 | static inline void | 310 | static inline void |
311 | __ip_set_put(ip_set_id_t index) | 311 | __ip_set_put(ip_set_id_t index) |
312 | { | 312 | { |
313 | write_lock_bh(&ip_set_ref_lock); | 313 | write_lock_bh(&ip_set_ref_lock); |
314 | BUG_ON(ip_set_list[index]->ref == 0); | 314 | BUG_ON(ip_set_list[index]->ref == 0); |
315 | ip_set_list[index]->ref--; | 315 | ip_set_list[index]->ref--; |
316 | write_unlock_bh(&ip_set_ref_lock); | 316 | write_unlock_bh(&ip_set_ref_lock); |
317 | } | 317 | } |
318 | 318 | ||
319 | /* | 319 | /* |
320 | * Add, del and test set entries from kernel. | 320 | * Add, del and test set entries from kernel. |
321 | * | 321 | * |
322 | * The set behind the index must exist and must be referenced | 322 | * The set behind the index must exist and must be referenced |
323 | * so it can't be destroyed (or changed) under our foot. | 323 | * so it can't be destroyed (or changed) under our foot. |
324 | */ | 324 | */ |
325 | 325 | ||
326 | int | 326 | int |
327 | ip_set_test(ip_set_id_t index, const struct sk_buff *skb, | 327 | ip_set_test(ip_set_id_t index, const struct sk_buff *skb, |
328 | const struct ip_set_adt_opt *opt) | 328 | const struct ip_set_adt_opt *opt) |
329 | { | 329 | { |
330 | struct ip_set *set = ip_set_list[index]; | 330 | struct ip_set *set = ip_set_list[index]; |
331 | int ret = 0; | 331 | int ret = 0; |
332 | 332 | ||
333 | BUG_ON(set == NULL); | 333 | BUG_ON(set == NULL); |
334 | pr_debug("set %s, index %u\n", set->name, index); | 334 | pr_debug("set %s, index %u\n", set->name, index); |
335 | 335 | ||
336 | if (opt->dim < set->type->dimension || | 336 | if (opt->dim < set->type->dimension || |
337 | !(opt->family == set->family || set->family == AF_UNSPEC)) | 337 | !(opt->family == set->family || set->family == AF_UNSPEC)) |
338 | return 0; | 338 | return 0; |
339 | 339 | ||
340 | read_lock_bh(&set->lock); | 340 | read_lock_bh(&set->lock); |
341 | ret = set->variant->kadt(set, skb, IPSET_TEST, opt); | 341 | ret = set->variant->kadt(set, skb, IPSET_TEST, opt); |
342 | read_unlock_bh(&set->lock); | 342 | read_unlock_bh(&set->lock); |
343 | 343 | ||
344 | if (ret == -EAGAIN) { | 344 | if (ret == -EAGAIN) { |
345 | /* Type requests element to be completed */ | 345 | /* Type requests element to be completed */ |
346 | pr_debug("element must be competed, ADD is triggered\n"); | 346 | pr_debug("element must be competed, ADD is triggered\n"); |
347 | write_lock_bh(&set->lock); | 347 | write_lock_bh(&set->lock); |
348 | set->variant->kadt(set, skb, IPSET_ADD, opt); | 348 | set->variant->kadt(set, skb, IPSET_ADD, opt); |
349 | write_unlock_bh(&set->lock); | 349 | write_unlock_bh(&set->lock); |
350 | ret = 1; | 350 | ret = 1; |
351 | } | 351 | } |
352 | 352 | ||
353 | /* Convert error codes to nomatch */ | 353 | /* Convert error codes to nomatch */ |
354 | return (ret < 0 ? 0 : ret); | 354 | return (ret < 0 ? 0 : ret); |
355 | } | 355 | } |
356 | EXPORT_SYMBOL_GPL(ip_set_test); | 356 | EXPORT_SYMBOL_GPL(ip_set_test); |
357 | 357 | ||
358 | int | 358 | int |
359 | ip_set_add(ip_set_id_t index, const struct sk_buff *skb, | 359 | ip_set_add(ip_set_id_t index, const struct sk_buff *skb, |
360 | const struct ip_set_adt_opt *opt) | 360 | const struct ip_set_adt_opt *opt) |
361 | { | 361 | { |
362 | struct ip_set *set = ip_set_list[index]; | 362 | struct ip_set *set = ip_set_list[index]; |
363 | int ret; | 363 | int ret; |
364 | 364 | ||
365 | BUG_ON(set == NULL); | 365 | BUG_ON(set == NULL); |
366 | pr_debug("set %s, index %u\n", set->name, index); | 366 | pr_debug("set %s, index %u\n", set->name, index); |
367 | 367 | ||
368 | if (opt->dim < set->type->dimension || | 368 | if (opt->dim < set->type->dimension || |
369 | !(opt->family == set->family || set->family == AF_UNSPEC)) | 369 | !(opt->family == set->family || set->family == AF_UNSPEC)) |
370 | return 0; | 370 | return 0; |
371 | 371 | ||
372 | write_lock_bh(&set->lock); | 372 | write_lock_bh(&set->lock); |
373 | ret = set->variant->kadt(set, skb, IPSET_ADD, opt); | 373 | ret = set->variant->kadt(set, skb, IPSET_ADD, opt); |
374 | write_unlock_bh(&set->lock); | 374 | write_unlock_bh(&set->lock); |
375 | 375 | ||
376 | return ret; | 376 | return ret; |
377 | } | 377 | } |
378 | EXPORT_SYMBOL_GPL(ip_set_add); | 378 | EXPORT_SYMBOL_GPL(ip_set_add); |
379 | 379 | ||
380 | int | 380 | int |
381 | ip_set_del(ip_set_id_t index, const struct sk_buff *skb, | 381 | ip_set_del(ip_set_id_t index, const struct sk_buff *skb, |
382 | const struct ip_set_adt_opt *opt) | 382 | const struct ip_set_adt_opt *opt) |
383 | { | 383 | { |
384 | struct ip_set *set = ip_set_list[index]; | 384 | struct ip_set *set = ip_set_list[index]; |
385 | int ret = 0; | 385 | int ret = 0; |
386 | 386 | ||
387 | BUG_ON(set == NULL); | 387 | BUG_ON(set == NULL); |
388 | pr_debug("set %s, index %u\n", set->name, index); | 388 | pr_debug("set %s, index %u\n", set->name, index); |
389 | 389 | ||
390 | if (opt->dim < set->type->dimension || | 390 | if (opt->dim < set->type->dimension || |
391 | !(opt->family == set->family || set->family == AF_UNSPEC)) | 391 | !(opt->family == set->family || set->family == AF_UNSPEC)) |
392 | return 0; | 392 | return 0; |
393 | 393 | ||
394 | write_lock_bh(&set->lock); | 394 | write_lock_bh(&set->lock); |
395 | ret = set->variant->kadt(set, skb, IPSET_DEL, opt); | 395 | ret = set->variant->kadt(set, skb, IPSET_DEL, opt); |
396 | write_unlock_bh(&set->lock); | 396 | write_unlock_bh(&set->lock); |
397 | 397 | ||
398 | return ret; | 398 | return ret; |
399 | } | 399 | } |
400 | EXPORT_SYMBOL_GPL(ip_set_del); | 400 | EXPORT_SYMBOL_GPL(ip_set_del); |
401 | 401 | ||
402 | /* | 402 | /* |
403 | * Find set by name, reference it once. The reference makes sure the | 403 | * Find set by name, reference it once. The reference makes sure the |
404 | * thing pointed to, does not go away under our feet. | 404 | * thing pointed to, does not go away under our feet. |
405 | * | 405 | * |
406 | */ | 406 | */ |
407 | ip_set_id_t | 407 | ip_set_id_t |
408 | ip_set_get_byname(const char *name, struct ip_set **set) | 408 | ip_set_get_byname(const char *name, struct ip_set **set) |
409 | { | 409 | { |
410 | ip_set_id_t i, index = IPSET_INVALID_ID; | 410 | ip_set_id_t i, index = IPSET_INVALID_ID; |
411 | struct ip_set *s; | 411 | struct ip_set *s; |
412 | 412 | ||
413 | for (i = 0; i < ip_set_max; i++) { | 413 | for (i = 0; i < ip_set_max; i++) { |
414 | s = ip_set_list[i]; | 414 | s = ip_set_list[i]; |
415 | if (s != NULL && STREQ(s->name, name)) { | 415 | if (s != NULL && STREQ(s->name, name)) { |
416 | __ip_set_get(i); | 416 | __ip_set_get(i); |
417 | index = i; | 417 | index = i; |
418 | *set = s; | 418 | *set = s; |
419 | } | 419 | } |
420 | } | 420 | } |
421 | 421 | ||
422 | return index; | 422 | return index; |
423 | } | 423 | } |
424 | EXPORT_SYMBOL_GPL(ip_set_get_byname); | 424 | EXPORT_SYMBOL_GPL(ip_set_get_byname); |
425 | 425 | ||
426 | /* | 426 | /* |
427 | * If the given set pointer points to a valid set, decrement | 427 | * If the given set pointer points to a valid set, decrement |
428 | * reference count by 1. The caller shall not assume the index | 428 | * reference count by 1. The caller shall not assume the index |
429 | * to be valid, after calling this function. | 429 | * to be valid, after calling this function. |
430 | * | 430 | * |
431 | */ | 431 | */ |
432 | void | 432 | void |
433 | ip_set_put_byindex(ip_set_id_t index) | 433 | ip_set_put_byindex(ip_set_id_t index) |
434 | { | 434 | { |
435 | if (ip_set_list[index] != NULL) | 435 | if (ip_set_list[index] != NULL) |
436 | __ip_set_put(index); | 436 | __ip_set_put(index); |
437 | } | 437 | } |
438 | EXPORT_SYMBOL_GPL(ip_set_put_byindex); | 438 | EXPORT_SYMBOL_GPL(ip_set_put_byindex); |
439 | 439 | ||
440 | /* | 440 | /* |
441 | * Get the name of a set behind a set index. | 441 | * Get the name of a set behind a set index. |
442 | * We assume the set is referenced, so it does exist and | 442 | * We assume the set is referenced, so it does exist and |
443 | * can't be destroyed. The set cannot be renamed due to | 443 | * can't be destroyed. The set cannot be renamed due to |
444 | * the referencing either. | 444 | * the referencing either. |
445 | * | 445 | * |
446 | */ | 446 | */ |
447 | const char * | 447 | const char * |
448 | ip_set_name_byindex(ip_set_id_t index) | 448 | ip_set_name_byindex(ip_set_id_t index) |
449 | { | 449 | { |
450 | const struct ip_set *set = ip_set_list[index]; | 450 | const struct ip_set *set = ip_set_list[index]; |
451 | 451 | ||
452 | BUG_ON(set == NULL); | 452 | BUG_ON(set == NULL); |
453 | BUG_ON(set->ref == 0); | 453 | BUG_ON(set->ref == 0); |
454 | 454 | ||
455 | /* Referenced, so it's safe */ | 455 | /* Referenced, so it's safe */ |
456 | return set->name; | 456 | return set->name; |
457 | } | 457 | } |
458 | EXPORT_SYMBOL_GPL(ip_set_name_byindex); | 458 | EXPORT_SYMBOL_GPL(ip_set_name_byindex); |
459 | 459 | ||
460 | /* | 460 | /* |
461 | * Routines to call by external subsystems, which do not | 461 | * Routines to call by external subsystems, which do not |
462 | * call nfnl_lock for us. | 462 | * call nfnl_lock for us. |
463 | */ | 463 | */ |
464 | 464 | ||
465 | /* | 465 | /* |
466 | * Find set by name, reference it once. The reference makes sure the | 466 | * Find set by name, reference it once. The reference makes sure the |
467 | * thing pointed to, does not go away under our feet. | 467 | * thing pointed to, does not go away under our feet. |
468 | * | 468 | * |
469 | * The nfnl mutex is used in the function. | 469 | * The nfnl mutex is used in the function. |
470 | */ | 470 | */ |
471 | ip_set_id_t | 471 | ip_set_id_t |
472 | ip_set_nfnl_get(const char *name) | 472 | ip_set_nfnl_get(const char *name) |
473 | { | 473 | { |
474 | struct ip_set *s; | 474 | struct ip_set *s; |
475 | ip_set_id_t index; | 475 | ip_set_id_t index; |
476 | 476 | ||
477 | nfnl_lock(); | 477 | nfnl_lock(); |
478 | index = ip_set_get_byname(name, &s); | 478 | index = ip_set_get_byname(name, &s); |
479 | nfnl_unlock(); | 479 | nfnl_unlock(); |
480 | 480 | ||
481 | return index; | 481 | return index; |
482 | } | 482 | } |
483 | EXPORT_SYMBOL_GPL(ip_set_nfnl_get); | 483 | EXPORT_SYMBOL_GPL(ip_set_nfnl_get); |
484 | 484 | ||
485 | /* | 485 | /* |
486 | * Find set by index, reference it once. The reference makes sure the | 486 | * Find set by index, reference it once. The reference makes sure the |
487 | * thing pointed to, does not go away under our feet. | 487 | * thing pointed to, does not go away under our feet. |
488 | * | 488 | * |
489 | * The nfnl mutex is used in the function. | 489 | * The nfnl mutex is used in the function. |
490 | */ | 490 | */ |
491 | ip_set_id_t | 491 | ip_set_id_t |
492 | ip_set_nfnl_get_byindex(ip_set_id_t index) | 492 | ip_set_nfnl_get_byindex(ip_set_id_t index) |
493 | { | 493 | { |
494 | if (index > ip_set_max) | 494 | if (index > ip_set_max) |
495 | return IPSET_INVALID_ID; | 495 | return IPSET_INVALID_ID; |
496 | 496 | ||
497 | nfnl_lock(); | 497 | nfnl_lock(); |
498 | if (ip_set_list[index]) | 498 | if (ip_set_list[index]) |
499 | __ip_set_get(index); | 499 | __ip_set_get(index); |
500 | else | 500 | else |
501 | index = IPSET_INVALID_ID; | 501 | index = IPSET_INVALID_ID; |
502 | nfnl_unlock(); | 502 | nfnl_unlock(); |
503 | 503 | ||
504 | return index; | 504 | return index; |
505 | } | 505 | } |
506 | EXPORT_SYMBOL_GPL(ip_set_nfnl_get_byindex); | 506 | EXPORT_SYMBOL_GPL(ip_set_nfnl_get_byindex); |
507 | 507 | ||
508 | /* | 508 | /* |
509 | * If the given set pointer points to a valid set, decrement | 509 | * If the given set pointer points to a valid set, decrement |
510 | * reference count by 1. The caller shall not assume the index | 510 | * reference count by 1. The caller shall not assume the index |
511 | * to be valid, after calling this function. | 511 | * to be valid, after calling this function. |
512 | * | 512 | * |
513 | * The nfnl mutex is used in the function. | 513 | * The nfnl mutex is used in the function. |
514 | */ | 514 | */ |
515 | void | 515 | void |
516 | ip_set_nfnl_put(ip_set_id_t index) | 516 | ip_set_nfnl_put(ip_set_id_t index) |
517 | { | 517 | { |
518 | nfnl_lock(); | 518 | nfnl_lock(); |
519 | ip_set_put_byindex(index); | 519 | ip_set_put_byindex(index); |
520 | nfnl_unlock(); | 520 | nfnl_unlock(); |
521 | } | 521 | } |
522 | EXPORT_SYMBOL_GPL(ip_set_nfnl_put); | 522 | EXPORT_SYMBOL_GPL(ip_set_nfnl_put); |
523 | 523 | ||
524 | /* | 524 | /* |
525 | * Communication protocol with userspace over netlink. | 525 | * Communication protocol with userspace over netlink. |
526 | * | 526 | * |
527 | * The commands are serialized by the nfnl mutex. | 527 | * The commands are serialized by the nfnl mutex. |
528 | */ | 528 | */ |
529 | 529 | ||
530 | static inline bool | 530 | static inline bool |
531 | protocol_failed(const struct nlattr * const tb[]) | 531 | protocol_failed(const struct nlattr * const tb[]) |
532 | { | 532 | { |
533 | return !tb[IPSET_ATTR_PROTOCOL] || | 533 | return !tb[IPSET_ATTR_PROTOCOL] || |
534 | nla_get_u8(tb[IPSET_ATTR_PROTOCOL]) != IPSET_PROTOCOL; | 534 | nla_get_u8(tb[IPSET_ATTR_PROTOCOL]) != IPSET_PROTOCOL; |
535 | } | 535 | } |
536 | 536 | ||
537 | static inline u32 | 537 | static inline u32 |
538 | flag_exist(const struct nlmsghdr *nlh) | 538 | flag_exist(const struct nlmsghdr *nlh) |
539 | { | 539 | { |
540 | return nlh->nlmsg_flags & NLM_F_EXCL ? 0 : IPSET_FLAG_EXIST; | 540 | return nlh->nlmsg_flags & NLM_F_EXCL ? 0 : IPSET_FLAG_EXIST; |
541 | } | 541 | } |
542 | 542 | ||
543 | static struct nlmsghdr * | 543 | static struct nlmsghdr * |
544 | start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags, | 544 | start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags, |
545 | enum ipset_cmd cmd) | 545 | enum ipset_cmd cmd) |
546 | { | 546 | { |
547 | struct nlmsghdr *nlh; | 547 | struct nlmsghdr *nlh; |
548 | struct nfgenmsg *nfmsg; | 548 | struct nfgenmsg *nfmsg; |
549 | 549 | ||
550 | nlh = nlmsg_put(skb, pid, seq, cmd | (NFNL_SUBSYS_IPSET << 8), | 550 | nlh = nlmsg_put(skb, pid, seq, cmd | (NFNL_SUBSYS_IPSET << 8), |
551 | sizeof(*nfmsg), flags); | 551 | sizeof(*nfmsg), flags); |
552 | if (nlh == NULL) | 552 | if (nlh == NULL) |
553 | return NULL; | 553 | return NULL; |
554 | 554 | ||
555 | nfmsg = nlmsg_data(nlh); | 555 | nfmsg = nlmsg_data(nlh); |
556 | nfmsg->nfgen_family = AF_INET; | 556 | nfmsg->nfgen_family = AF_INET; |
557 | nfmsg->version = NFNETLINK_V0; | 557 | nfmsg->version = NFNETLINK_V0; |
558 | nfmsg->res_id = 0; | 558 | nfmsg->res_id = 0; |
559 | 559 | ||
560 | return nlh; | 560 | return nlh; |
561 | } | 561 | } |
562 | 562 | ||
563 | /* Create a set */ | 563 | /* Create a set */ |
564 | 564 | ||
565 | static const struct nla_policy ip_set_create_policy[IPSET_ATTR_CMD_MAX + 1] = { | 565 | static const struct nla_policy ip_set_create_policy[IPSET_ATTR_CMD_MAX + 1] = { |
566 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, | 566 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, |
567 | [IPSET_ATTR_SETNAME] = { .type = NLA_NUL_STRING, | 567 | [IPSET_ATTR_SETNAME] = { .type = NLA_NUL_STRING, |
568 | .len = IPSET_MAXNAMELEN - 1 }, | 568 | .len = IPSET_MAXNAMELEN - 1 }, |
569 | [IPSET_ATTR_TYPENAME] = { .type = NLA_NUL_STRING, | 569 | [IPSET_ATTR_TYPENAME] = { .type = NLA_NUL_STRING, |
570 | .len = IPSET_MAXNAMELEN - 1}, | 570 | .len = IPSET_MAXNAMELEN - 1}, |
571 | [IPSET_ATTR_REVISION] = { .type = NLA_U8 }, | 571 | [IPSET_ATTR_REVISION] = { .type = NLA_U8 }, |
572 | [IPSET_ATTR_FAMILY] = { .type = NLA_U8 }, | 572 | [IPSET_ATTR_FAMILY] = { .type = NLA_U8 }, |
573 | [IPSET_ATTR_DATA] = { .type = NLA_NESTED }, | 573 | [IPSET_ATTR_DATA] = { .type = NLA_NESTED }, |
574 | }; | 574 | }; |
575 | 575 | ||
576 | static ip_set_id_t | 576 | static ip_set_id_t |
577 | find_set_id(const char *name) | 577 | find_set_id(const char *name) |
578 | { | 578 | { |
579 | ip_set_id_t i, index = IPSET_INVALID_ID; | 579 | ip_set_id_t i, index = IPSET_INVALID_ID; |
580 | const struct ip_set *set; | 580 | const struct ip_set *set; |
581 | 581 | ||
582 | for (i = 0; index == IPSET_INVALID_ID && i < ip_set_max; i++) { | 582 | for (i = 0; index == IPSET_INVALID_ID && i < ip_set_max; i++) { |
583 | set = ip_set_list[i]; | 583 | set = ip_set_list[i]; |
584 | if (set != NULL && STREQ(set->name, name)) | 584 | if (set != NULL && STREQ(set->name, name)) |
585 | index = i; | 585 | index = i; |
586 | } | 586 | } |
587 | return index; | 587 | return index; |
588 | } | 588 | } |
589 | 589 | ||
590 | static inline struct ip_set * | 590 | static inline struct ip_set * |
591 | find_set(const char *name) | 591 | find_set(const char *name) |
592 | { | 592 | { |
593 | ip_set_id_t index = find_set_id(name); | 593 | ip_set_id_t index = find_set_id(name); |
594 | 594 | ||
595 | return index == IPSET_INVALID_ID ? NULL : ip_set_list[index]; | 595 | return index == IPSET_INVALID_ID ? NULL : ip_set_list[index]; |
596 | } | 596 | } |
597 | 597 | ||
598 | static int | 598 | static int |
599 | find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set) | 599 | find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set) |
600 | { | 600 | { |
601 | ip_set_id_t i; | 601 | ip_set_id_t i; |
602 | 602 | ||
603 | *index = IPSET_INVALID_ID; | 603 | *index = IPSET_INVALID_ID; |
604 | for (i = 0; i < ip_set_max; i++) { | 604 | for (i = 0; i < ip_set_max; i++) { |
605 | if (ip_set_list[i] == NULL) { | 605 | if (ip_set_list[i] == NULL) { |
606 | if (*index == IPSET_INVALID_ID) | 606 | if (*index == IPSET_INVALID_ID) |
607 | *index = i; | 607 | *index = i; |
608 | } else if (STREQ(name, ip_set_list[i]->name)) { | 608 | } else if (STREQ(name, ip_set_list[i]->name)) { |
609 | /* Name clash */ | 609 | /* Name clash */ |
610 | *set = ip_set_list[i]; | 610 | *set = ip_set_list[i]; |
611 | return -EEXIST; | 611 | return -EEXIST; |
612 | } | 612 | } |
613 | } | 613 | } |
614 | if (*index == IPSET_INVALID_ID) | 614 | if (*index == IPSET_INVALID_ID) |
615 | /* No free slot remained */ | 615 | /* No free slot remained */ |
616 | return -IPSET_ERR_MAX_SETS; | 616 | return -IPSET_ERR_MAX_SETS; |
617 | return 0; | 617 | return 0; |
618 | } | 618 | } |
619 | 619 | ||
620 | static int | 620 | static int |
621 | ip_set_create(struct sock *ctnl, struct sk_buff *skb, | 621 | ip_set_create(struct sock *ctnl, struct sk_buff *skb, |
622 | const struct nlmsghdr *nlh, | 622 | const struct nlmsghdr *nlh, |
623 | const struct nlattr * const attr[]) | 623 | const struct nlattr * const attr[]) |
624 | { | 624 | { |
625 | struct ip_set *set, *clash = NULL; | 625 | struct ip_set *set, *clash = NULL; |
626 | ip_set_id_t index = IPSET_INVALID_ID; | 626 | ip_set_id_t index = IPSET_INVALID_ID; |
627 | struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {}; | 627 | struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {}; |
628 | const char *name, *typename; | 628 | const char *name, *typename; |
629 | u8 family, revision; | 629 | u8 family, revision; |
630 | u32 flags = flag_exist(nlh); | 630 | u32 flags = flag_exist(nlh); |
631 | int ret = 0; | 631 | int ret = 0; |
632 | 632 | ||
633 | if (unlikely(protocol_failed(attr) || | 633 | if (unlikely(protocol_failed(attr) || |
634 | attr[IPSET_ATTR_SETNAME] == NULL || | 634 | attr[IPSET_ATTR_SETNAME] == NULL || |
635 | attr[IPSET_ATTR_TYPENAME] == NULL || | 635 | attr[IPSET_ATTR_TYPENAME] == NULL || |
636 | attr[IPSET_ATTR_REVISION] == NULL || | 636 | attr[IPSET_ATTR_REVISION] == NULL || |
637 | attr[IPSET_ATTR_FAMILY] == NULL || | 637 | attr[IPSET_ATTR_FAMILY] == NULL || |
638 | (attr[IPSET_ATTR_DATA] != NULL && | 638 | (attr[IPSET_ATTR_DATA] != NULL && |
639 | !flag_nested(attr[IPSET_ATTR_DATA])))) | 639 | !flag_nested(attr[IPSET_ATTR_DATA])))) |
640 | return -IPSET_ERR_PROTOCOL; | 640 | return -IPSET_ERR_PROTOCOL; |
641 | 641 | ||
642 | name = nla_data(attr[IPSET_ATTR_SETNAME]); | 642 | name = nla_data(attr[IPSET_ATTR_SETNAME]); |
643 | typename = nla_data(attr[IPSET_ATTR_TYPENAME]); | 643 | typename = nla_data(attr[IPSET_ATTR_TYPENAME]); |
644 | family = nla_get_u8(attr[IPSET_ATTR_FAMILY]); | 644 | family = nla_get_u8(attr[IPSET_ATTR_FAMILY]); |
645 | revision = nla_get_u8(attr[IPSET_ATTR_REVISION]); | 645 | revision = nla_get_u8(attr[IPSET_ATTR_REVISION]); |
646 | pr_debug("setname: %s, typename: %s, family: %s, revision: %u\n", | 646 | pr_debug("setname: %s, typename: %s, family: %s, revision: %u\n", |
647 | name, typename, family_name(family), revision); | 647 | name, typename, family_name(family), revision); |
648 | 648 | ||
649 | /* | 649 | /* |
650 | * First, and without any locks, allocate and initialize | 650 | * First, and without any locks, allocate and initialize |
651 | * a normal base set structure. | 651 | * a normal base set structure. |
652 | */ | 652 | */ |
653 | set = kzalloc(sizeof(struct ip_set), GFP_KERNEL); | 653 | set = kzalloc(sizeof(struct ip_set), GFP_KERNEL); |
654 | if (!set) | 654 | if (!set) |
655 | return -ENOMEM; | 655 | return -ENOMEM; |
656 | rwlock_init(&set->lock); | 656 | rwlock_init(&set->lock); |
657 | strlcpy(set->name, name, IPSET_MAXNAMELEN); | 657 | strlcpy(set->name, name, IPSET_MAXNAMELEN); |
658 | set->family = family; | 658 | set->family = family; |
659 | 659 | ||
660 | /* | 660 | /* |
661 | * Next, check that we know the type, and take | 661 | * Next, check that we know the type, and take |
662 | * a reference on the type, to make sure it stays available | 662 | * a reference on the type, to make sure it stays available |
663 | * while constructing our new set. | 663 | * while constructing our new set. |
664 | * | 664 | * |
665 | * After referencing the type, we try to create the type | 665 | * After referencing the type, we try to create the type |
666 | * specific part of the set without holding any locks. | 666 | * specific part of the set without holding any locks. |
667 | */ | 667 | */ |
668 | ret = find_set_type_get(typename, family, revision, &(set->type)); | 668 | ret = find_set_type_get(typename, family, revision, &(set->type)); |
669 | if (ret) | 669 | if (ret) |
670 | goto out; | 670 | goto out; |
671 | 671 | ||
672 | /* | 672 | /* |
673 | * Without holding any locks, create private part. | 673 | * Without holding any locks, create private part. |
674 | */ | 674 | */ |
675 | if (attr[IPSET_ATTR_DATA] && | 675 | if (attr[IPSET_ATTR_DATA] && |
676 | nla_parse_nested(tb, IPSET_ATTR_CREATE_MAX, attr[IPSET_ATTR_DATA], | 676 | nla_parse_nested(tb, IPSET_ATTR_CREATE_MAX, attr[IPSET_ATTR_DATA], |
677 | set->type->create_policy)) { | 677 | set->type->create_policy)) { |
678 | ret = -IPSET_ERR_PROTOCOL; | 678 | ret = -IPSET_ERR_PROTOCOL; |
679 | goto put_out; | 679 | goto put_out; |
680 | } | 680 | } |
681 | 681 | ||
682 | ret = set->type->create(set, tb, flags); | 682 | ret = set->type->create(set, tb, flags); |
683 | if (ret != 0) | 683 | if (ret != 0) |
684 | goto put_out; | 684 | goto put_out; |
685 | 685 | ||
686 | /* BTW, ret==0 here. */ | 686 | /* BTW, ret==0 here. */ |
687 | 687 | ||
688 | /* | 688 | /* |
689 | * Here, we have a valid, constructed set and we are protected | 689 | * Here, we have a valid, constructed set and we are protected |
690 | * by the nfnl mutex. Find the first free index in ip_set_list | 690 | * by the nfnl mutex. Find the first free index in ip_set_list |
691 | * and check clashing. | 691 | * and check clashing. |
692 | */ | 692 | */ |
693 | if ((ret = find_free_id(set->name, &index, &clash)) != 0) { | 693 | if ((ret = find_free_id(set->name, &index, &clash)) != 0) { |
694 | /* If this is the same set and requested, ignore error */ | 694 | /* If this is the same set and requested, ignore error */ |
695 | if (ret == -EEXIST && | 695 | if (ret == -EEXIST && |
696 | (flags & IPSET_FLAG_EXIST) && | 696 | (flags & IPSET_FLAG_EXIST) && |
697 | STREQ(set->type->name, clash->type->name) && | 697 | STREQ(set->type->name, clash->type->name) && |
698 | set->type->family == clash->type->family && | 698 | set->type->family == clash->type->family && |
699 | set->type->revision == clash->type->revision && | 699 | set->type->revision == clash->type->revision && |
700 | set->variant->same_set(set, clash)) | 700 | set->variant->same_set(set, clash)) |
701 | ret = 0; | 701 | ret = 0; |
702 | goto cleanup; | 702 | goto cleanup; |
703 | } | 703 | } |
704 | 704 | ||
705 | /* | 705 | /* |
706 | * Finally! Add our shiny new set to the list, and be done. | 706 | * Finally! Add our shiny new set to the list, and be done. |
707 | */ | 707 | */ |
708 | pr_debug("create: '%s' created with index %u!\n", set->name, index); | 708 | pr_debug("create: '%s' created with index %u!\n", set->name, index); |
709 | ip_set_list[index] = set; | 709 | ip_set_list[index] = set; |
710 | 710 | ||
711 | return ret; | 711 | return ret; |
712 | 712 | ||
713 | cleanup: | 713 | cleanup: |
714 | set->variant->destroy(set); | 714 | set->variant->destroy(set); |
715 | put_out: | 715 | put_out: |
716 | module_put(set->type->me); | 716 | module_put(set->type->me); |
717 | out: | 717 | out: |
718 | kfree(set); | 718 | kfree(set); |
719 | return ret; | 719 | return ret; |
720 | } | 720 | } |
721 | 721 | ||
722 | /* Destroy sets */ | 722 | /* Destroy sets */ |
723 | 723 | ||
724 | static const struct nla_policy | 724 | static const struct nla_policy |
725 | ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = { | 725 | ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = { |
726 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, | 726 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, |
727 | [IPSET_ATTR_SETNAME] = { .type = NLA_NUL_STRING, | 727 | [IPSET_ATTR_SETNAME] = { .type = NLA_NUL_STRING, |
728 | .len = IPSET_MAXNAMELEN - 1 }, | 728 | .len = IPSET_MAXNAMELEN - 1 }, |
729 | }; | 729 | }; |
730 | 730 | ||
731 | static void | 731 | static void |
732 | ip_set_destroy_set(ip_set_id_t index) | 732 | ip_set_destroy_set(ip_set_id_t index) |
733 | { | 733 | { |
734 | struct ip_set *set = ip_set_list[index]; | 734 | struct ip_set *set = ip_set_list[index]; |
735 | 735 | ||
736 | pr_debug("set: %s\n", set->name); | 736 | pr_debug("set: %s\n", set->name); |
737 | ip_set_list[index] = NULL; | 737 | ip_set_list[index] = NULL; |
738 | 738 | ||
739 | /* Must call it without holding any lock */ | 739 | /* Must call it without holding any lock */ |
740 | set->variant->destroy(set); | 740 | set->variant->destroy(set); |
741 | module_put(set->type->me); | 741 | module_put(set->type->me); |
742 | kfree(set); | 742 | kfree(set); |
743 | } | 743 | } |
744 | 744 | ||
745 | static int | 745 | static int |
746 | ip_set_destroy(struct sock *ctnl, struct sk_buff *skb, | 746 | ip_set_destroy(struct sock *ctnl, struct sk_buff *skb, |
747 | const struct nlmsghdr *nlh, | 747 | const struct nlmsghdr *nlh, |
748 | const struct nlattr * const attr[]) | 748 | const struct nlattr * const attr[]) |
749 | { | 749 | { |
750 | ip_set_id_t i; | 750 | ip_set_id_t i; |
751 | int ret = 0; | 751 | int ret = 0; |
752 | 752 | ||
753 | if (unlikely(protocol_failed(attr))) | 753 | if (unlikely(protocol_failed(attr))) |
754 | return -IPSET_ERR_PROTOCOL; | 754 | return -IPSET_ERR_PROTOCOL; |
755 | 755 | ||
756 | /* Commands are serialized and references are | 756 | /* Commands are serialized and references are |
757 | * protected by the ip_set_ref_lock. | 757 | * protected by the ip_set_ref_lock. |
758 | * External systems (i.e. xt_set) must call | 758 | * External systems (i.e. xt_set) must call |
759 | * ip_set_put|get_nfnl_* functions, that way we | 759 | * ip_set_put|get_nfnl_* functions, that way we |
760 | * can safely check references here. | 760 | * can safely check references here. |
761 | * | 761 | * |
762 | * list:set timer can only decrement the reference | 762 | * list:set timer can only decrement the reference |
763 | * counter, so if it's already zero, we can proceed | 763 | * counter, so if it's already zero, we can proceed |
764 | * without holding the lock. | 764 | * without holding the lock. |
765 | */ | 765 | */ |
766 | read_lock_bh(&ip_set_ref_lock); | 766 | read_lock_bh(&ip_set_ref_lock); |
767 | if (!attr[IPSET_ATTR_SETNAME]) { | 767 | if (!attr[IPSET_ATTR_SETNAME]) { |
768 | for (i = 0; i < ip_set_max; i++) { | 768 | for (i = 0; i < ip_set_max; i++) { |
769 | if (ip_set_list[i] != NULL && ip_set_list[i]->ref) { | 769 | if (ip_set_list[i] != NULL && ip_set_list[i]->ref) { |
770 | ret = IPSET_ERR_BUSY; | 770 | ret = IPSET_ERR_BUSY; |
771 | goto out; | 771 | goto out; |
772 | } | 772 | } |
773 | } | 773 | } |
774 | read_unlock_bh(&ip_set_ref_lock); | 774 | read_unlock_bh(&ip_set_ref_lock); |
775 | for (i = 0; i < ip_set_max; i++) { | 775 | for (i = 0; i < ip_set_max; i++) { |
776 | if (ip_set_list[i] != NULL) | 776 | if (ip_set_list[i] != NULL) |
777 | ip_set_destroy_set(i); | 777 | ip_set_destroy_set(i); |
778 | } | 778 | } |
779 | } else { | 779 | } else { |
780 | i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); | 780 | i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); |
781 | if (i == IPSET_INVALID_ID) { | 781 | if (i == IPSET_INVALID_ID) { |
782 | ret = -ENOENT; | 782 | ret = -ENOENT; |
783 | goto out; | 783 | goto out; |
784 | } else if (ip_set_list[i]->ref) { | 784 | } else if (ip_set_list[i]->ref) { |
785 | ret = -IPSET_ERR_BUSY; | 785 | ret = -IPSET_ERR_BUSY; |
786 | goto out; | 786 | goto out; |
787 | } | 787 | } |
788 | read_unlock_bh(&ip_set_ref_lock); | 788 | read_unlock_bh(&ip_set_ref_lock); |
789 | 789 | ||
790 | ip_set_destroy_set(i); | 790 | ip_set_destroy_set(i); |
791 | } | 791 | } |
792 | return 0; | 792 | return 0; |
793 | out: | 793 | out: |
794 | read_unlock_bh(&ip_set_ref_lock); | 794 | read_unlock_bh(&ip_set_ref_lock); |
795 | return ret; | 795 | return ret; |
796 | } | 796 | } |
797 | 797 | ||
798 | /* Flush sets */ | 798 | /* Flush sets */ |
799 | 799 | ||
800 | static void | 800 | static void |
801 | ip_set_flush_set(struct ip_set *set) | 801 | ip_set_flush_set(struct ip_set *set) |
802 | { | 802 | { |
803 | pr_debug("set: %s\n", set->name); | 803 | pr_debug("set: %s\n", set->name); |
804 | 804 | ||
805 | write_lock_bh(&set->lock); | 805 | write_lock_bh(&set->lock); |
806 | set->variant->flush(set); | 806 | set->variant->flush(set); |
807 | write_unlock_bh(&set->lock); | 807 | write_unlock_bh(&set->lock); |
808 | } | 808 | } |
809 | 809 | ||
810 | static int | 810 | static int |
811 | ip_set_flush(struct sock *ctnl, struct sk_buff *skb, | 811 | ip_set_flush(struct sock *ctnl, struct sk_buff *skb, |
812 | const struct nlmsghdr *nlh, | 812 | const struct nlmsghdr *nlh, |
813 | const struct nlattr * const attr[]) | 813 | const struct nlattr * const attr[]) |
814 | { | 814 | { |
815 | ip_set_id_t i; | 815 | ip_set_id_t i; |
816 | 816 | ||
817 | if (unlikely(protocol_failed(attr))) | 817 | if (unlikely(protocol_failed(attr))) |
818 | return -IPSET_ERR_PROTOCOL; | 818 | return -IPSET_ERR_PROTOCOL; |
819 | 819 | ||
820 | if (!attr[IPSET_ATTR_SETNAME]) { | 820 | if (!attr[IPSET_ATTR_SETNAME]) { |
821 | for (i = 0; i < ip_set_max; i++) | 821 | for (i = 0; i < ip_set_max; i++) |
822 | if (ip_set_list[i] != NULL) | 822 | if (ip_set_list[i] != NULL) |
823 | ip_set_flush_set(ip_set_list[i]); | 823 | ip_set_flush_set(ip_set_list[i]); |
824 | } else { | 824 | } else { |
825 | i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); | 825 | i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); |
826 | if (i == IPSET_INVALID_ID) | 826 | if (i == IPSET_INVALID_ID) |
827 | return -ENOENT; | 827 | return -ENOENT; |
828 | 828 | ||
829 | ip_set_flush_set(ip_set_list[i]); | 829 | ip_set_flush_set(ip_set_list[i]); |
830 | } | 830 | } |
831 | 831 | ||
832 | return 0; | 832 | return 0; |
833 | } | 833 | } |
834 | 834 | ||
835 | /* Rename a set */ | 835 | /* Rename a set */ |
836 | 836 | ||
837 | static const struct nla_policy | 837 | static const struct nla_policy |
838 | ip_set_setname2_policy[IPSET_ATTR_CMD_MAX + 1] = { | 838 | ip_set_setname2_policy[IPSET_ATTR_CMD_MAX + 1] = { |
839 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, | 839 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, |
840 | [IPSET_ATTR_SETNAME] = { .type = NLA_NUL_STRING, | 840 | [IPSET_ATTR_SETNAME] = { .type = NLA_NUL_STRING, |
841 | .len = IPSET_MAXNAMELEN - 1 }, | 841 | .len = IPSET_MAXNAMELEN - 1 }, |
842 | [IPSET_ATTR_SETNAME2] = { .type = NLA_NUL_STRING, | 842 | [IPSET_ATTR_SETNAME2] = { .type = NLA_NUL_STRING, |
843 | .len = IPSET_MAXNAMELEN - 1 }, | 843 | .len = IPSET_MAXNAMELEN - 1 }, |
844 | }; | 844 | }; |
845 | 845 | ||
846 | static int | 846 | static int |
847 | ip_set_rename(struct sock *ctnl, struct sk_buff *skb, | 847 | ip_set_rename(struct sock *ctnl, struct sk_buff *skb, |
848 | const struct nlmsghdr *nlh, | 848 | const struct nlmsghdr *nlh, |
849 | const struct nlattr * const attr[]) | 849 | const struct nlattr * const attr[]) |
850 | { | 850 | { |
851 | struct ip_set *set; | 851 | struct ip_set *set; |
852 | const char *name2; | 852 | const char *name2; |
853 | ip_set_id_t i; | 853 | ip_set_id_t i; |
854 | int ret = 0; | 854 | int ret = 0; |
855 | 855 | ||
856 | if (unlikely(protocol_failed(attr) || | 856 | if (unlikely(protocol_failed(attr) || |
857 | attr[IPSET_ATTR_SETNAME] == NULL || | 857 | attr[IPSET_ATTR_SETNAME] == NULL || |
858 | attr[IPSET_ATTR_SETNAME2] == NULL)) | 858 | attr[IPSET_ATTR_SETNAME2] == NULL)) |
859 | return -IPSET_ERR_PROTOCOL; | 859 | return -IPSET_ERR_PROTOCOL; |
860 | 860 | ||
861 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); | 861 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); |
862 | if (set == NULL) | 862 | if (set == NULL) |
863 | return -ENOENT; | 863 | return -ENOENT; |
864 | 864 | ||
865 | read_lock_bh(&ip_set_ref_lock); | 865 | read_lock_bh(&ip_set_ref_lock); |
866 | if (set->ref != 0) { | 866 | if (set->ref != 0) { |
867 | ret = -IPSET_ERR_REFERENCED; | 867 | ret = -IPSET_ERR_REFERENCED; |
868 | goto out; | 868 | goto out; |
869 | } | 869 | } |
870 | 870 | ||
871 | name2 = nla_data(attr[IPSET_ATTR_SETNAME2]); | 871 | name2 = nla_data(attr[IPSET_ATTR_SETNAME2]); |
872 | for (i = 0; i < ip_set_max; i++) { | 872 | for (i = 0; i < ip_set_max; i++) { |
873 | if (ip_set_list[i] != NULL && | 873 | if (ip_set_list[i] != NULL && |
874 | STREQ(ip_set_list[i]->name, name2)) { | 874 | STREQ(ip_set_list[i]->name, name2)) { |
875 | ret = -IPSET_ERR_EXIST_SETNAME2; | 875 | ret = -IPSET_ERR_EXIST_SETNAME2; |
876 | goto out; | 876 | goto out; |
877 | } | 877 | } |
878 | } | 878 | } |
879 | strncpy(set->name, name2, IPSET_MAXNAMELEN); | 879 | strncpy(set->name, name2, IPSET_MAXNAMELEN); |
880 | 880 | ||
881 | out: | 881 | out: |
882 | read_unlock_bh(&ip_set_ref_lock); | 882 | read_unlock_bh(&ip_set_ref_lock); |
883 | return ret; | 883 | return ret; |
884 | } | 884 | } |
885 | 885 | ||
886 | /* Swap two sets so that name/index points to the other. | 886 | /* Swap two sets so that name/index points to the other. |
887 | * References and set names are also swapped. | 887 | * References and set names are also swapped. |
888 | * | 888 | * |
889 | * The commands are serialized by the nfnl mutex and references are | 889 | * The commands are serialized by the nfnl mutex and references are |
890 | * protected by the ip_set_ref_lock. The kernel interfaces | 890 | * protected by the ip_set_ref_lock. The kernel interfaces |
891 | * do not hold the mutex but the pointer settings are atomic | 891 | * do not hold the mutex but the pointer settings are atomic |
892 | * so the ip_set_list always contains valid pointers to the sets. | 892 | * so the ip_set_list always contains valid pointers to the sets. |
893 | */ | 893 | */ |
894 | 894 | ||
895 | static int | 895 | static int |
896 | ip_set_swap(struct sock *ctnl, struct sk_buff *skb, | 896 | ip_set_swap(struct sock *ctnl, struct sk_buff *skb, |
897 | const struct nlmsghdr *nlh, | 897 | const struct nlmsghdr *nlh, |
898 | const struct nlattr * const attr[]) | 898 | const struct nlattr * const attr[]) |
899 | { | 899 | { |
900 | struct ip_set *from, *to; | 900 | struct ip_set *from, *to; |
901 | ip_set_id_t from_id, to_id; | 901 | ip_set_id_t from_id, to_id; |
902 | char from_name[IPSET_MAXNAMELEN]; | 902 | char from_name[IPSET_MAXNAMELEN]; |
903 | 903 | ||
904 | if (unlikely(protocol_failed(attr) || | 904 | if (unlikely(protocol_failed(attr) || |
905 | attr[IPSET_ATTR_SETNAME] == NULL || | 905 | attr[IPSET_ATTR_SETNAME] == NULL || |
906 | attr[IPSET_ATTR_SETNAME2] == NULL)) | 906 | attr[IPSET_ATTR_SETNAME2] == NULL)) |
907 | return -IPSET_ERR_PROTOCOL; | 907 | return -IPSET_ERR_PROTOCOL; |
908 | 908 | ||
909 | from_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); | 909 | from_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); |
910 | if (from_id == IPSET_INVALID_ID) | 910 | if (from_id == IPSET_INVALID_ID) |
911 | return -ENOENT; | 911 | return -ENOENT; |
912 | 912 | ||
913 | to_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME2])); | 913 | to_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME2])); |
914 | if (to_id == IPSET_INVALID_ID) | 914 | if (to_id == IPSET_INVALID_ID) |
915 | return -IPSET_ERR_EXIST_SETNAME2; | 915 | return -IPSET_ERR_EXIST_SETNAME2; |
916 | 916 | ||
917 | from = ip_set_list[from_id]; | 917 | from = ip_set_list[from_id]; |
918 | to = ip_set_list[to_id]; | 918 | to = ip_set_list[to_id]; |
919 | 919 | ||
920 | /* Features must not change. | 920 | /* Features must not change. |
921 | * Not an artificial restriction anymore, as we must prevent | 921 | * Not an artificial restriction anymore, as we must prevent |
922 | * possible loops created by swapping in setlist type of sets. */ | 922 | * possible loops created by swapping in setlist type of sets. */ |
923 | if (!(from->type->features == to->type->features && | 923 | if (!(from->type->features == to->type->features && |
924 | from->type->family == to->type->family)) | 924 | from->type->family == to->type->family)) |
925 | return -IPSET_ERR_TYPE_MISMATCH; | 925 | return -IPSET_ERR_TYPE_MISMATCH; |
926 | 926 | ||
927 | strncpy(from_name, from->name, IPSET_MAXNAMELEN); | 927 | strncpy(from_name, from->name, IPSET_MAXNAMELEN); |
928 | strncpy(from->name, to->name, IPSET_MAXNAMELEN); | 928 | strncpy(from->name, to->name, IPSET_MAXNAMELEN); |
929 | strncpy(to->name, from_name, IPSET_MAXNAMELEN); | 929 | strncpy(to->name, from_name, IPSET_MAXNAMELEN); |
930 | 930 | ||
931 | write_lock_bh(&ip_set_ref_lock); | 931 | write_lock_bh(&ip_set_ref_lock); |
932 | swap(from->ref, to->ref); | 932 | swap(from->ref, to->ref); |
933 | ip_set_list[from_id] = to; | 933 | ip_set_list[from_id] = to; |
934 | ip_set_list[to_id] = from; | 934 | ip_set_list[to_id] = from; |
935 | write_unlock_bh(&ip_set_ref_lock); | 935 | write_unlock_bh(&ip_set_ref_lock); |
936 | 936 | ||
937 | return 0; | 937 | return 0; |
938 | } | 938 | } |
939 | 939 | ||
940 | /* List/save set data */ | 940 | /* List/save set data */ |
941 | 941 | ||
942 | #define DUMP_INIT 0L | 942 | #define DUMP_INIT 0 |
943 | #define DUMP_ALL 1L | 943 | #define DUMP_ALL 1 |
944 | #define DUMP_ONE 2L | 944 | #define DUMP_ONE 2 |
945 | #define DUMP_LAST 3L | 945 | #define DUMP_LAST 3 |
946 | 946 | ||
947 | #define DUMP_TYPE(arg) (((u32)(arg)) & 0x0000FFFF) | ||
948 | #define DUMP_FLAGS(arg) (((u32)(arg)) >> 16) | ||
949 | |||
947 | static int | 950 | static int |
948 | ip_set_dump_done(struct netlink_callback *cb) | 951 | ip_set_dump_done(struct netlink_callback *cb) |
949 | { | 952 | { |
950 | if (cb->args[2]) { | 953 | if (cb->args[2]) { |
951 | pr_debug("release set %s\n", ip_set_list[cb->args[1]]->name); | 954 | pr_debug("release set %s\n", ip_set_list[cb->args[1]]->name); |
952 | ip_set_put_byindex((ip_set_id_t) cb->args[1]); | 955 | ip_set_put_byindex((ip_set_id_t) cb->args[1]); |
953 | } | 956 | } |
954 | return 0; | 957 | return 0; |
955 | } | 958 | } |
956 | 959 | ||
957 | static inline void | 960 | static inline void |
958 | dump_attrs(struct nlmsghdr *nlh) | 961 | dump_attrs(struct nlmsghdr *nlh) |
959 | { | 962 | { |
960 | const struct nlattr *attr; | 963 | const struct nlattr *attr; |
961 | int rem; | 964 | int rem; |
962 | 965 | ||
963 | pr_debug("dump nlmsg\n"); | 966 | pr_debug("dump nlmsg\n"); |
964 | nlmsg_for_each_attr(attr, nlh, sizeof(struct nfgenmsg), rem) { | 967 | nlmsg_for_each_attr(attr, nlh, sizeof(struct nfgenmsg), rem) { |
965 | pr_debug("type: %u, len %u\n", nla_type(attr), attr->nla_len); | 968 | pr_debug("type: %u, len %u\n", nla_type(attr), attr->nla_len); |
966 | } | 969 | } |
967 | } | 970 | } |
968 | 971 | ||
969 | static int | 972 | static int |
970 | dump_init(struct netlink_callback *cb) | 973 | dump_init(struct netlink_callback *cb) |
971 | { | 974 | { |
972 | struct nlmsghdr *nlh = nlmsg_hdr(cb->skb); | 975 | struct nlmsghdr *nlh = nlmsg_hdr(cb->skb); |
973 | int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); | 976 | int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); |
974 | struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; | 977 | struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; |
975 | struct nlattr *attr = (void *)nlh + min_len; | 978 | struct nlattr *attr = (void *)nlh + min_len; |
979 | u32 dump_type; | ||
976 | ip_set_id_t index; | 980 | ip_set_id_t index; |
977 | 981 | ||
978 | /* Second pass, so parser can't fail */ | 982 | /* Second pass, so parser can't fail */ |
979 | nla_parse(cda, IPSET_ATTR_CMD_MAX, | 983 | nla_parse(cda, IPSET_ATTR_CMD_MAX, |
980 | attr, nlh->nlmsg_len - min_len, ip_set_setname_policy); | 984 | attr, nlh->nlmsg_len - min_len, ip_set_setname_policy); |
981 | 985 | ||
982 | /* cb->args[0] : dump single set/all sets | 986 | /* cb->args[0] : dump single set/all sets |
983 | * [1] : set index | 987 | * [1] : set index |
984 | * [..]: type specific | 988 | * [..]: type specific |
985 | */ | 989 | */ |
986 | 990 | ||
987 | if (!cda[IPSET_ATTR_SETNAME]) { | 991 | if (cda[IPSET_ATTR_SETNAME]) { |
988 | cb->args[0] = DUMP_ALL; | 992 | index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME])); |
989 | return 0; | 993 | if (index == IPSET_INVALID_ID) |
990 | } | 994 | return -ENOENT; |
991 | 995 | ||
992 | index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME])); | 996 | dump_type = DUMP_ONE; |
993 | if (index == IPSET_INVALID_ID) | 997 | cb->args[1] = index; |
994 | return -ENOENT; | 998 | } else |
999 | dump_type = DUMP_ALL; | ||
995 | 1000 | ||
996 | cb->args[0] = DUMP_ONE; | 1001 | if (cda[IPSET_ATTR_FLAGS]) { |
997 | cb->args[1] = index; | 1002 | u32 f = ip_set_get_h32(cda[IPSET_ATTR_FLAGS]); |
1003 | dump_type |= (f << 16); | ||
1004 | } | ||
1005 | cb->args[0] = dump_type; | ||
1006 | |||
998 | return 0; | 1007 | return 0; |
999 | } | 1008 | } |
1000 | 1009 | ||
1001 | static int | 1010 | static int |
1002 | ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) | 1011 | ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) |
1003 | { | 1012 | { |
1004 | ip_set_id_t index = IPSET_INVALID_ID, max; | 1013 | ip_set_id_t index = IPSET_INVALID_ID, max; |
1005 | struct ip_set *set = NULL; | 1014 | struct ip_set *set = NULL; |
1006 | struct nlmsghdr *nlh = NULL; | 1015 | struct nlmsghdr *nlh = NULL; |
1007 | unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0; | 1016 | unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0; |
1017 | u32 dump_type, dump_flags; | ||
1008 | int ret = 0; | 1018 | int ret = 0; |
1009 | 1019 | ||
1010 | if (cb->args[0] == DUMP_INIT) { | 1020 | if (!cb->args[0]) { |
1011 | ret = dump_init(cb); | 1021 | ret = dump_init(cb); |
1012 | if (ret < 0) { | 1022 | if (ret < 0) { |
1013 | nlh = nlmsg_hdr(cb->skb); | 1023 | nlh = nlmsg_hdr(cb->skb); |
1014 | /* We have to create and send the error message | 1024 | /* We have to create and send the error message |
1015 | * manually :-( */ | 1025 | * manually :-( */ |
1016 | if (nlh->nlmsg_flags & NLM_F_ACK) | 1026 | if (nlh->nlmsg_flags & NLM_F_ACK) |
1017 | netlink_ack(cb->skb, nlh, ret); | 1027 | netlink_ack(cb->skb, nlh, ret); |
1018 | return ret; | 1028 | return ret; |
1019 | } | 1029 | } |
1020 | } | 1030 | } |
1021 | 1031 | ||
1022 | if (cb->args[1] >= ip_set_max) | 1032 | if (cb->args[1] >= ip_set_max) |
1023 | goto out; | 1033 | goto out; |
1024 | 1034 | ||
1025 | max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max; | 1035 | dump_type = DUMP_TYPE(cb->args[0]); |
1036 | dump_flags = DUMP_FLAGS(cb->args[0]); | ||
1037 | max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max; | ||
1026 | dump_last: | 1038 | dump_last: |
1027 | pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]); | 1039 | pr_debug("args[0]: %u %u args[1]: %ld\n", |
1040 | dump_type, dump_flags, cb->args[1]); | ||
1028 | for (; cb->args[1] < max; cb->args[1]++) { | 1041 | for (; cb->args[1] < max; cb->args[1]++) { |
1029 | index = (ip_set_id_t) cb->args[1]; | 1042 | index = (ip_set_id_t) cb->args[1]; |
1030 | set = ip_set_list[index]; | 1043 | set = ip_set_list[index]; |
1031 | if (set == NULL) { | 1044 | if (set == NULL) { |
1032 | if (cb->args[0] == DUMP_ONE) { | 1045 | if (dump_type == DUMP_ONE) { |
1033 | ret = -ENOENT; | 1046 | ret = -ENOENT; |
1034 | goto out; | 1047 | goto out; |
1035 | } | 1048 | } |
1036 | continue; | 1049 | continue; |
1037 | } | 1050 | } |
1038 | /* When dumping all sets, we must dump "sorted" | 1051 | /* When dumping all sets, we must dump "sorted" |
1039 | * so that lists (unions of sets) are dumped last. | 1052 | * so that lists (unions of sets) are dumped last. |
1040 | */ | 1053 | */ |
1041 | if (cb->args[0] != DUMP_ONE && | 1054 | if (dump_type != DUMP_ONE && |
1042 | ((cb->args[0] == DUMP_ALL) == | 1055 | ((dump_type == DUMP_ALL) == |
1043 | !!(set->type->features & IPSET_DUMP_LAST))) | 1056 | !!(set->type->features & IPSET_DUMP_LAST))) |
1044 | continue; | 1057 | continue; |
1045 | pr_debug("List set: %s\n", set->name); | 1058 | pr_debug("List set: %s\n", set->name); |
1046 | if (!cb->args[2]) { | 1059 | if (!cb->args[2]) { |
1047 | /* Start listing: make sure set won't be destroyed */ | 1060 | /* Start listing: make sure set won't be destroyed */ |
1048 | pr_debug("reference set\n"); | 1061 | pr_debug("reference set\n"); |
1049 | __ip_set_get(index); | 1062 | __ip_set_get(index); |
1050 | } | 1063 | } |
1051 | nlh = start_msg(skb, NETLINK_CB(cb->skb).pid, | 1064 | nlh = start_msg(skb, NETLINK_CB(cb->skb).pid, |
1052 | cb->nlh->nlmsg_seq, flags, | 1065 | cb->nlh->nlmsg_seq, flags, |
1053 | IPSET_CMD_LIST); | 1066 | IPSET_CMD_LIST); |
1054 | if (!nlh) { | 1067 | if (!nlh) { |
1055 | ret = -EMSGSIZE; | 1068 | ret = -EMSGSIZE; |
1056 | goto release_refcount; | 1069 | goto release_refcount; |
1057 | } | 1070 | } |
1058 | NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); | 1071 | NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); |
1059 | NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name); | 1072 | NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name); |
1073 | if (dump_flags & IPSET_FLAG_LIST_SETNAME) | ||
1074 | goto next_set; | ||
1060 | switch (cb->args[2]) { | 1075 | switch (cb->args[2]) { |
1061 | case 0: | 1076 | case 0: |
1062 | /* Core header data */ | 1077 | /* Core header data */ |
1063 | NLA_PUT_STRING(skb, IPSET_ATTR_TYPENAME, | 1078 | NLA_PUT_STRING(skb, IPSET_ATTR_TYPENAME, |
1064 | set->type->name); | 1079 | set->type->name); |
1065 | NLA_PUT_U8(skb, IPSET_ATTR_FAMILY, | 1080 | NLA_PUT_U8(skb, IPSET_ATTR_FAMILY, |
1066 | set->family); | 1081 | set->family); |
1067 | NLA_PUT_U8(skb, IPSET_ATTR_REVISION, | 1082 | NLA_PUT_U8(skb, IPSET_ATTR_REVISION, |
1068 | set->type->revision); | 1083 | set->type->revision); |
1069 | ret = set->variant->head(set, skb); | 1084 | ret = set->variant->head(set, skb); |
1070 | if (ret < 0) | 1085 | if (ret < 0) |
1071 | goto release_refcount; | 1086 | goto release_refcount; |
1087 | if (dump_flags & IPSET_FLAG_LIST_HEADER) | ||
1088 | goto next_set; | ||
1072 | /* Fall through and add elements */ | 1089 | /* Fall through and add elements */ |
1073 | default: | 1090 | default: |
1074 | read_lock_bh(&set->lock); | 1091 | read_lock_bh(&set->lock); |
1075 | ret = set->variant->list(set, skb, cb); | 1092 | ret = set->variant->list(set, skb, cb); |
1076 | read_unlock_bh(&set->lock); | 1093 | read_unlock_bh(&set->lock); |
1077 | if (!cb->args[2]) { | 1094 | if (!cb->args[2]) |
1078 | /* Set is done, proceed with next one */ | 1095 | /* Set is done, proceed with next one */ |
1079 | if (cb->args[0] == DUMP_ONE) | 1096 | goto next_set; |
1080 | cb->args[1] = IPSET_INVALID_ID; | ||
1081 | else | ||
1082 | cb->args[1]++; | ||
1083 | } | ||
1084 | goto release_refcount; | 1097 | goto release_refcount; |
1085 | } | 1098 | } |
1086 | } | 1099 | } |
1087 | /* If we dump all sets, continue with dumping last ones */ | 1100 | /* If we dump all sets, continue with dumping last ones */ |
1088 | if (cb->args[0] == DUMP_ALL) { | 1101 | if (dump_type == DUMP_ALL) { |
1089 | cb->args[0] = DUMP_LAST; | 1102 | dump_type = DUMP_LAST; |
1103 | cb->args[0] = dump_type | (dump_flags << 16); | ||
1090 | cb->args[1] = 0; | 1104 | cb->args[1] = 0; |
1091 | goto dump_last; | 1105 | goto dump_last; |
1092 | } | 1106 | } |
1093 | goto out; | 1107 | goto out; |
1094 | 1108 | ||
1095 | nla_put_failure: | 1109 | nla_put_failure: |
1096 | ret = -EFAULT; | 1110 | ret = -EFAULT; |
1111 | next_set: | ||
1112 | if (dump_type == DUMP_ONE) | ||
1113 | cb->args[1] = IPSET_INVALID_ID; | ||
1114 | else | ||
1115 | cb->args[1]++; | ||
1097 | release_refcount: | 1116 | release_refcount: |
1098 | /* If there was an error or set is done, release set */ | 1117 | /* If there was an error or set is done, release set */ |
1099 | if (ret || !cb->args[2]) { | 1118 | if (ret || !cb->args[2]) { |
1100 | pr_debug("release set %s\n", ip_set_list[index]->name); | 1119 | pr_debug("release set %s\n", ip_set_list[index]->name); |
1101 | ip_set_put_byindex(index); | 1120 | ip_set_put_byindex(index); |
1102 | } | 1121 | } |
1103 | out: | 1122 | out: |
1104 | if (nlh) { | 1123 | if (nlh) { |
1105 | nlmsg_end(skb, nlh); | 1124 | nlmsg_end(skb, nlh); |
1106 | pr_debug("nlmsg_len: %u\n", nlh->nlmsg_len); | 1125 | pr_debug("nlmsg_len: %u\n", nlh->nlmsg_len); |
1107 | dump_attrs(nlh); | 1126 | dump_attrs(nlh); |
1108 | } | 1127 | } |
1109 | 1128 | ||
1110 | return ret < 0 ? ret : skb->len; | 1129 | return ret < 0 ? ret : skb->len; |
1111 | } | 1130 | } |
1112 | 1131 | ||
1113 | static int | 1132 | static int |
1114 | ip_set_dump(struct sock *ctnl, struct sk_buff *skb, | 1133 | ip_set_dump(struct sock *ctnl, struct sk_buff *skb, |
1115 | const struct nlmsghdr *nlh, | 1134 | const struct nlmsghdr *nlh, |
1116 | const struct nlattr * const attr[]) | 1135 | const struct nlattr * const attr[]) |
1117 | { | 1136 | { |
1118 | if (unlikely(protocol_failed(attr))) | 1137 | if (unlikely(protocol_failed(attr))) |
1119 | return -IPSET_ERR_PROTOCOL; | 1138 | return -IPSET_ERR_PROTOCOL; |
1120 | 1139 | ||
1121 | return netlink_dump_start(ctnl, skb, nlh, | 1140 | return netlink_dump_start(ctnl, skb, nlh, |
1122 | ip_set_dump_start, | 1141 | ip_set_dump_start, |
1123 | ip_set_dump_done, 0); | 1142 | ip_set_dump_done, 0); |
1124 | } | 1143 | } |
1125 | 1144 | ||
1126 | /* Add, del and test */ | 1145 | /* Add, del and test */ |
1127 | 1146 | ||
1128 | static const struct nla_policy ip_set_adt_policy[IPSET_ATTR_CMD_MAX + 1] = { | 1147 | static const struct nla_policy ip_set_adt_policy[IPSET_ATTR_CMD_MAX + 1] = { |
1129 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, | 1148 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, |
1130 | [IPSET_ATTR_SETNAME] = { .type = NLA_NUL_STRING, | 1149 | [IPSET_ATTR_SETNAME] = { .type = NLA_NUL_STRING, |
1131 | .len = IPSET_MAXNAMELEN - 1 }, | 1150 | .len = IPSET_MAXNAMELEN - 1 }, |
1132 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | 1151 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
1133 | [IPSET_ATTR_DATA] = { .type = NLA_NESTED }, | 1152 | [IPSET_ATTR_DATA] = { .type = NLA_NESTED }, |
1134 | [IPSET_ATTR_ADT] = { .type = NLA_NESTED }, | 1153 | [IPSET_ATTR_ADT] = { .type = NLA_NESTED }, |
1135 | }; | 1154 | }; |
1136 | 1155 | ||
1137 | static int | 1156 | static int |
1138 | call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, | 1157 | call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, |
1139 | struct nlattr *tb[], enum ipset_adt adt, | 1158 | struct nlattr *tb[], enum ipset_adt adt, |
1140 | u32 flags, bool use_lineno) | 1159 | u32 flags, bool use_lineno) |
1141 | { | 1160 | { |
1142 | int ret, retried = 0; | 1161 | int ret, retried = 0; |
1143 | u32 lineno = 0; | 1162 | u32 lineno = 0; |
1144 | bool eexist = flags & IPSET_FLAG_EXIST; | 1163 | bool eexist = flags & IPSET_FLAG_EXIST; |
1145 | 1164 | ||
1146 | do { | 1165 | do { |
1147 | write_lock_bh(&set->lock); | 1166 | write_lock_bh(&set->lock); |
1148 | ret = set->variant->uadt(set, tb, adt, &lineno, flags); | 1167 | ret = set->variant->uadt(set, tb, adt, &lineno, flags); |
1149 | write_unlock_bh(&set->lock); | 1168 | write_unlock_bh(&set->lock); |
1150 | } while (ret == -EAGAIN && | 1169 | } while (ret == -EAGAIN && |
1151 | set->variant->resize && | 1170 | set->variant->resize && |
1152 | (ret = set->variant->resize(set, retried++)) == 0); | 1171 | (ret = set->variant->resize(set, retried++)) == 0); |
1153 | 1172 | ||
1154 | if (!ret || (ret == -IPSET_ERR_EXIST && eexist)) | 1173 | if (!ret || (ret == -IPSET_ERR_EXIST && eexist)) |
1155 | return 0; | 1174 | return 0; |
1156 | if (lineno && use_lineno) { | 1175 | if (lineno && use_lineno) { |
1157 | /* Error in restore/batch mode: send back lineno */ | 1176 | /* Error in restore/batch mode: send back lineno */ |
1158 | struct nlmsghdr *rep, *nlh = nlmsg_hdr(skb); | 1177 | struct nlmsghdr *rep, *nlh = nlmsg_hdr(skb); |
1159 | struct sk_buff *skb2; | 1178 | struct sk_buff *skb2; |
1160 | struct nlmsgerr *errmsg; | 1179 | struct nlmsgerr *errmsg; |
1161 | size_t payload = sizeof(*errmsg) + nlmsg_len(nlh); | 1180 | size_t payload = sizeof(*errmsg) + nlmsg_len(nlh); |
1162 | int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); | 1181 | int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); |
1163 | struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; | 1182 | struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; |
1164 | struct nlattr *cmdattr; | 1183 | struct nlattr *cmdattr; |
1165 | u32 *errline; | 1184 | u32 *errline; |
1166 | 1185 | ||
1167 | skb2 = nlmsg_new(payload, GFP_KERNEL); | 1186 | skb2 = nlmsg_new(payload, GFP_KERNEL); |
1168 | if (skb2 == NULL) | 1187 | if (skb2 == NULL) |
1169 | return -ENOMEM; | 1188 | return -ENOMEM; |
1170 | rep = __nlmsg_put(skb2, NETLINK_CB(skb).pid, | 1189 | rep = __nlmsg_put(skb2, NETLINK_CB(skb).pid, |
1171 | nlh->nlmsg_seq, NLMSG_ERROR, payload, 0); | 1190 | nlh->nlmsg_seq, NLMSG_ERROR, payload, 0); |
1172 | errmsg = nlmsg_data(rep); | 1191 | errmsg = nlmsg_data(rep); |
1173 | errmsg->error = ret; | 1192 | errmsg->error = ret; |
1174 | memcpy(&errmsg->msg, nlh, nlh->nlmsg_len); | 1193 | memcpy(&errmsg->msg, nlh, nlh->nlmsg_len); |
1175 | cmdattr = (void *)&errmsg->msg + min_len; | 1194 | cmdattr = (void *)&errmsg->msg + min_len; |
1176 | 1195 | ||
1177 | nla_parse(cda, IPSET_ATTR_CMD_MAX, | 1196 | nla_parse(cda, IPSET_ATTR_CMD_MAX, |
1178 | cmdattr, nlh->nlmsg_len - min_len, | 1197 | cmdattr, nlh->nlmsg_len - min_len, |
1179 | ip_set_adt_policy); | 1198 | ip_set_adt_policy); |
1180 | 1199 | ||
1181 | errline = nla_data(cda[IPSET_ATTR_LINENO]); | 1200 | errline = nla_data(cda[IPSET_ATTR_LINENO]); |
1182 | 1201 | ||
1183 | *errline = lineno; | 1202 | *errline = lineno; |
1184 | 1203 | ||
1185 | netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | 1204 | netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); |
1186 | /* Signal netlink not to send its ACK/errmsg. */ | 1205 | /* Signal netlink not to send its ACK/errmsg. */ |
1187 | return -EINTR; | 1206 | return -EINTR; |
1188 | } | 1207 | } |
1189 | 1208 | ||
1190 | return ret; | 1209 | return ret; |
1191 | } | 1210 | } |
1192 | 1211 | ||
1193 | static int | 1212 | static int |
1194 | ip_set_uadd(struct sock *ctnl, struct sk_buff *skb, | 1213 | ip_set_uadd(struct sock *ctnl, struct sk_buff *skb, |
1195 | const struct nlmsghdr *nlh, | 1214 | const struct nlmsghdr *nlh, |
1196 | const struct nlattr * const attr[]) | 1215 | const struct nlattr * const attr[]) |
1197 | { | 1216 | { |
1198 | struct ip_set *set; | 1217 | struct ip_set *set; |
1199 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; | 1218 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; |
1200 | const struct nlattr *nla; | 1219 | const struct nlattr *nla; |
1201 | u32 flags = flag_exist(nlh); | 1220 | u32 flags = flag_exist(nlh); |
1202 | bool use_lineno; | 1221 | bool use_lineno; |
1203 | int ret = 0; | 1222 | int ret = 0; |
1204 | 1223 | ||
1205 | if (unlikely(protocol_failed(attr) || | 1224 | if (unlikely(protocol_failed(attr) || |
1206 | attr[IPSET_ATTR_SETNAME] == NULL || | 1225 | attr[IPSET_ATTR_SETNAME] == NULL || |
1207 | !((attr[IPSET_ATTR_DATA] != NULL) ^ | 1226 | !((attr[IPSET_ATTR_DATA] != NULL) ^ |
1208 | (attr[IPSET_ATTR_ADT] != NULL)) || | 1227 | (attr[IPSET_ATTR_ADT] != NULL)) || |
1209 | (attr[IPSET_ATTR_DATA] != NULL && | 1228 | (attr[IPSET_ATTR_DATA] != NULL && |
1210 | !flag_nested(attr[IPSET_ATTR_DATA])) || | 1229 | !flag_nested(attr[IPSET_ATTR_DATA])) || |
1211 | (attr[IPSET_ATTR_ADT] != NULL && | 1230 | (attr[IPSET_ATTR_ADT] != NULL && |
1212 | (!flag_nested(attr[IPSET_ATTR_ADT]) || | 1231 | (!flag_nested(attr[IPSET_ATTR_ADT]) || |
1213 | attr[IPSET_ATTR_LINENO] == NULL)))) | 1232 | attr[IPSET_ATTR_LINENO] == NULL)))) |
1214 | return -IPSET_ERR_PROTOCOL; | 1233 | return -IPSET_ERR_PROTOCOL; |
1215 | 1234 | ||
1216 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); | 1235 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); |
1217 | if (set == NULL) | 1236 | if (set == NULL) |
1218 | return -ENOENT; | 1237 | return -ENOENT; |
1219 | 1238 | ||
1220 | use_lineno = !!attr[IPSET_ATTR_LINENO]; | 1239 | use_lineno = !!attr[IPSET_ATTR_LINENO]; |
1221 | if (attr[IPSET_ATTR_DATA]) { | 1240 | if (attr[IPSET_ATTR_DATA]) { |
1222 | if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, | 1241 | if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, |
1223 | attr[IPSET_ATTR_DATA], | 1242 | attr[IPSET_ATTR_DATA], |
1224 | set->type->adt_policy)) | 1243 | set->type->adt_policy)) |
1225 | return -IPSET_ERR_PROTOCOL; | 1244 | return -IPSET_ERR_PROTOCOL; |
1226 | ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, flags, | 1245 | ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, flags, |
1227 | use_lineno); | 1246 | use_lineno); |
1228 | } else { | 1247 | } else { |
1229 | int nla_rem; | 1248 | int nla_rem; |
1230 | 1249 | ||
1231 | nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) { | 1250 | nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) { |
1232 | memset(tb, 0, sizeof(tb)); | 1251 | memset(tb, 0, sizeof(tb)); |
1233 | if (nla_type(nla) != IPSET_ATTR_DATA || | 1252 | if (nla_type(nla) != IPSET_ATTR_DATA || |
1234 | !flag_nested(nla) || | 1253 | !flag_nested(nla) || |
1235 | nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, | 1254 | nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, |
1236 | set->type->adt_policy)) | 1255 | set->type->adt_policy)) |
1237 | return -IPSET_ERR_PROTOCOL; | 1256 | return -IPSET_ERR_PROTOCOL; |
1238 | ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, | 1257 | ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, |
1239 | flags, use_lineno); | 1258 | flags, use_lineno); |
1240 | if (ret < 0) | 1259 | if (ret < 0) |
1241 | return ret; | 1260 | return ret; |
1242 | } | 1261 | } |
1243 | } | 1262 | } |
1244 | return ret; | 1263 | return ret; |
1245 | } | 1264 | } |
1246 | 1265 | ||
1247 | static int | 1266 | static int |
1248 | ip_set_udel(struct sock *ctnl, struct sk_buff *skb, | 1267 | ip_set_udel(struct sock *ctnl, struct sk_buff *skb, |
1249 | const struct nlmsghdr *nlh, | 1268 | const struct nlmsghdr *nlh, |
1250 | const struct nlattr * const attr[]) | 1269 | const struct nlattr * const attr[]) |
1251 | { | 1270 | { |
1252 | struct ip_set *set; | 1271 | struct ip_set *set; |
1253 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; | 1272 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; |
1254 | const struct nlattr *nla; | 1273 | const struct nlattr *nla; |
1255 | u32 flags = flag_exist(nlh); | 1274 | u32 flags = flag_exist(nlh); |
1256 | bool use_lineno; | 1275 | bool use_lineno; |
1257 | int ret = 0; | 1276 | int ret = 0; |
1258 | 1277 | ||
1259 | if (unlikely(protocol_failed(attr) || | 1278 | if (unlikely(protocol_failed(attr) || |
1260 | attr[IPSET_ATTR_SETNAME] == NULL || | 1279 | attr[IPSET_ATTR_SETNAME] == NULL || |
1261 | !((attr[IPSET_ATTR_DATA] != NULL) ^ | 1280 | !((attr[IPSET_ATTR_DATA] != NULL) ^ |
1262 | (attr[IPSET_ATTR_ADT] != NULL)) || | 1281 | (attr[IPSET_ATTR_ADT] != NULL)) || |
1263 | (attr[IPSET_ATTR_DATA] != NULL && | 1282 | (attr[IPSET_ATTR_DATA] != NULL && |
1264 | !flag_nested(attr[IPSET_ATTR_DATA])) || | 1283 | !flag_nested(attr[IPSET_ATTR_DATA])) || |
1265 | (attr[IPSET_ATTR_ADT] != NULL && | 1284 | (attr[IPSET_ATTR_ADT] != NULL && |
1266 | (!flag_nested(attr[IPSET_ATTR_ADT]) || | 1285 | (!flag_nested(attr[IPSET_ATTR_ADT]) || |
1267 | attr[IPSET_ATTR_LINENO] == NULL)))) | 1286 | attr[IPSET_ATTR_LINENO] == NULL)))) |
1268 | return -IPSET_ERR_PROTOCOL; | 1287 | return -IPSET_ERR_PROTOCOL; |
1269 | 1288 | ||
1270 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); | 1289 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); |
1271 | if (set == NULL) | 1290 | if (set == NULL) |
1272 | return -ENOENT; | 1291 | return -ENOENT; |
1273 | 1292 | ||
1274 | use_lineno = !!attr[IPSET_ATTR_LINENO]; | 1293 | use_lineno = !!attr[IPSET_ATTR_LINENO]; |
1275 | if (attr[IPSET_ATTR_DATA]) { | 1294 | if (attr[IPSET_ATTR_DATA]) { |
1276 | if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, | 1295 | if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, |
1277 | attr[IPSET_ATTR_DATA], | 1296 | attr[IPSET_ATTR_DATA], |
1278 | set->type->adt_policy)) | 1297 | set->type->adt_policy)) |
1279 | return -IPSET_ERR_PROTOCOL; | 1298 | return -IPSET_ERR_PROTOCOL; |
1280 | ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, flags, | 1299 | ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, flags, |
1281 | use_lineno); | 1300 | use_lineno); |
1282 | } else { | 1301 | } else { |
1283 | int nla_rem; | 1302 | int nla_rem; |
1284 | 1303 | ||
1285 | nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) { | 1304 | nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) { |
1286 | memset(tb, 0, sizeof(*tb)); | 1305 | memset(tb, 0, sizeof(*tb)); |
1287 | if (nla_type(nla) != IPSET_ATTR_DATA || | 1306 | if (nla_type(nla) != IPSET_ATTR_DATA || |
1288 | !flag_nested(nla) || | 1307 | !flag_nested(nla) || |
1289 | nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, | 1308 | nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, |
1290 | set->type->adt_policy)) | 1309 | set->type->adt_policy)) |
1291 | return -IPSET_ERR_PROTOCOL; | 1310 | return -IPSET_ERR_PROTOCOL; |
1292 | ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, | 1311 | ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, |
1293 | flags, use_lineno); | 1312 | flags, use_lineno); |
1294 | if (ret < 0) | 1313 | if (ret < 0) |
1295 | return ret; | 1314 | return ret; |
1296 | } | 1315 | } |
1297 | } | 1316 | } |
1298 | return ret; | 1317 | return ret; |
1299 | } | 1318 | } |
1300 | 1319 | ||
1301 | static int | 1320 | static int |
1302 | ip_set_utest(struct sock *ctnl, struct sk_buff *skb, | 1321 | ip_set_utest(struct sock *ctnl, struct sk_buff *skb, |
1303 | const struct nlmsghdr *nlh, | 1322 | const struct nlmsghdr *nlh, |
1304 | const struct nlattr * const attr[]) | 1323 | const struct nlattr * const attr[]) |
1305 | { | 1324 | { |
1306 | struct ip_set *set; | 1325 | struct ip_set *set; |
1307 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; | 1326 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; |
1308 | int ret = 0; | 1327 | int ret = 0; |
1309 | 1328 | ||
1310 | if (unlikely(protocol_failed(attr) || | 1329 | if (unlikely(protocol_failed(attr) || |
1311 | attr[IPSET_ATTR_SETNAME] == NULL || | 1330 | attr[IPSET_ATTR_SETNAME] == NULL || |
1312 | attr[IPSET_ATTR_DATA] == NULL || | 1331 | attr[IPSET_ATTR_DATA] == NULL || |
1313 | !flag_nested(attr[IPSET_ATTR_DATA]))) | 1332 | !flag_nested(attr[IPSET_ATTR_DATA]))) |
1314 | return -IPSET_ERR_PROTOCOL; | 1333 | return -IPSET_ERR_PROTOCOL; |
1315 | 1334 | ||
1316 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); | 1335 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); |
1317 | if (set == NULL) | 1336 | if (set == NULL) |
1318 | return -ENOENT; | 1337 | return -ENOENT; |
1319 | 1338 | ||
1320 | if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, attr[IPSET_ATTR_DATA], | 1339 | if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, attr[IPSET_ATTR_DATA], |
1321 | set->type->adt_policy)) | 1340 | set->type->adt_policy)) |
1322 | return -IPSET_ERR_PROTOCOL; | 1341 | return -IPSET_ERR_PROTOCOL; |
1323 | 1342 | ||
1324 | read_lock_bh(&set->lock); | 1343 | read_lock_bh(&set->lock); |
1325 | ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0); | 1344 | ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0); |
1326 | read_unlock_bh(&set->lock); | 1345 | read_unlock_bh(&set->lock); |
1327 | /* Userspace can't trigger element to be re-added */ | 1346 | /* Userspace can't trigger element to be re-added */ |
1328 | if (ret == -EAGAIN) | 1347 | if (ret == -EAGAIN) |
1329 | ret = 1; | 1348 | ret = 1; |
1330 | 1349 | ||
1331 | return ret < 0 ? ret : ret > 0 ? 0 : -IPSET_ERR_EXIST; | 1350 | return ret < 0 ? ret : ret > 0 ? 0 : -IPSET_ERR_EXIST; |
1332 | } | 1351 | } |
1333 | 1352 | ||
1334 | /* Get headed data of a set */ | 1353 | /* Get headed data of a set */ |
1335 | 1354 | ||
1336 | static int | 1355 | static int |
1337 | ip_set_header(struct sock *ctnl, struct sk_buff *skb, | 1356 | ip_set_header(struct sock *ctnl, struct sk_buff *skb, |
1338 | const struct nlmsghdr *nlh, | 1357 | const struct nlmsghdr *nlh, |
1339 | const struct nlattr * const attr[]) | 1358 | const struct nlattr * const attr[]) |
1340 | { | 1359 | { |
1341 | const struct ip_set *set; | 1360 | const struct ip_set *set; |
1342 | struct sk_buff *skb2; | 1361 | struct sk_buff *skb2; |
1343 | struct nlmsghdr *nlh2; | 1362 | struct nlmsghdr *nlh2; |
1344 | ip_set_id_t index; | 1363 | ip_set_id_t index; |
1345 | int ret = 0; | 1364 | int ret = 0; |
1346 | 1365 | ||
1347 | if (unlikely(protocol_failed(attr) || | 1366 | if (unlikely(protocol_failed(attr) || |
1348 | attr[IPSET_ATTR_SETNAME] == NULL)) | 1367 | attr[IPSET_ATTR_SETNAME] == NULL)) |
1349 | return -IPSET_ERR_PROTOCOL; | 1368 | return -IPSET_ERR_PROTOCOL; |
1350 | 1369 | ||
1351 | index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); | 1370 | index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); |
1352 | if (index == IPSET_INVALID_ID) | 1371 | if (index == IPSET_INVALID_ID) |
1353 | return -ENOENT; | 1372 | return -ENOENT; |
1354 | set = ip_set_list[index]; | 1373 | set = ip_set_list[index]; |
1355 | 1374 | ||
1356 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1375 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1357 | if (skb2 == NULL) | 1376 | if (skb2 == NULL) |
1358 | return -ENOMEM; | 1377 | return -ENOMEM; |
1359 | 1378 | ||
1360 | nlh2 = start_msg(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, | 1379 | nlh2 = start_msg(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, |
1361 | IPSET_CMD_HEADER); | 1380 | IPSET_CMD_HEADER); |
1362 | if (!nlh2) | 1381 | if (!nlh2) |
1363 | goto nlmsg_failure; | 1382 | goto nlmsg_failure; |
1364 | NLA_PUT_U8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); | 1383 | NLA_PUT_U8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); |
1365 | NLA_PUT_STRING(skb2, IPSET_ATTR_SETNAME, set->name); | 1384 | NLA_PUT_STRING(skb2, IPSET_ATTR_SETNAME, set->name); |
1366 | NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, set->type->name); | 1385 | NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, set->type->name); |
1367 | NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, set->family); | 1386 | NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, set->family); |
1368 | NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->type->revision); | 1387 | NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->type->revision); |
1369 | nlmsg_end(skb2, nlh2); | 1388 | nlmsg_end(skb2, nlh2); |
1370 | 1389 | ||
1371 | ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | 1390 | ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); |
1372 | if (ret < 0) | 1391 | if (ret < 0) |
1373 | return ret; | 1392 | return ret; |
1374 | 1393 | ||
1375 | return 0; | 1394 | return 0; |
1376 | 1395 | ||
1377 | nla_put_failure: | 1396 | nla_put_failure: |
1378 | nlmsg_cancel(skb2, nlh2); | 1397 | nlmsg_cancel(skb2, nlh2); |
1379 | nlmsg_failure: | 1398 | nlmsg_failure: |
1380 | kfree_skb(skb2); | 1399 | kfree_skb(skb2); |
1381 | return -EMSGSIZE; | 1400 | return -EMSGSIZE; |
1382 | } | 1401 | } |
1383 | 1402 | ||
1384 | /* Get type data */ | 1403 | /* Get type data */ |
1385 | 1404 | ||
1386 | static const struct nla_policy ip_set_type_policy[IPSET_ATTR_CMD_MAX + 1] = { | 1405 | static const struct nla_policy ip_set_type_policy[IPSET_ATTR_CMD_MAX + 1] = { |
1387 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, | 1406 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, |
1388 | [IPSET_ATTR_TYPENAME] = { .type = NLA_NUL_STRING, | 1407 | [IPSET_ATTR_TYPENAME] = { .type = NLA_NUL_STRING, |
1389 | .len = IPSET_MAXNAMELEN - 1 }, | 1408 | .len = IPSET_MAXNAMELEN - 1 }, |
1390 | [IPSET_ATTR_FAMILY] = { .type = NLA_U8 }, | 1409 | [IPSET_ATTR_FAMILY] = { .type = NLA_U8 }, |
1391 | }; | 1410 | }; |
1392 | 1411 | ||
1393 | static int | 1412 | static int |
1394 | ip_set_type(struct sock *ctnl, struct sk_buff *skb, | 1413 | ip_set_type(struct sock *ctnl, struct sk_buff *skb, |
1395 | const struct nlmsghdr *nlh, | 1414 | const struct nlmsghdr *nlh, |
1396 | const struct nlattr * const attr[]) | 1415 | const struct nlattr * const attr[]) |
1397 | { | 1416 | { |
1398 | struct sk_buff *skb2; | 1417 | struct sk_buff *skb2; |
1399 | struct nlmsghdr *nlh2; | 1418 | struct nlmsghdr *nlh2; |
1400 | u8 family, min, max; | 1419 | u8 family, min, max; |
1401 | const char *typename; | 1420 | const char *typename; |
1402 | int ret = 0; | 1421 | int ret = 0; |
1403 | 1422 | ||
1404 | if (unlikely(protocol_failed(attr) || | 1423 | if (unlikely(protocol_failed(attr) || |
1405 | attr[IPSET_ATTR_TYPENAME] == NULL || | 1424 | attr[IPSET_ATTR_TYPENAME] == NULL || |
1406 | attr[IPSET_ATTR_FAMILY] == NULL)) | 1425 | attr[IPSET_ATTR_FAMILY] == NULL)) |
1407 | return -IPSET_ERR_PROTOCOL; | 1426 | return -IPSET_ERR_PROTOCOL; |
1408 | 1427 | ||
1409 | family = nla_get_u8(attr[IPSET_ATTR_FAMILY]); | 1428 | family = nla_get_u8(attr[IPSET_ATTR_FAMILY]); |
1410 | typename = nla_data(attr[IPSET_ATTR_TYPENAME]); | 1429 | typename = nla_data(attr[IPSET_ATTR_TYPENAME]); |
1411 | ret = find_set_type_minmax(typename, family, &min, &max); | 1430 | ret = find_set_type_minmax(typename, family, &min, &max); |
1412 | if (ret) | 1431 | if (ret) |
1413 | return ret; | 1432 | return ret; |
1414 | 1433 | ||
1415 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1434 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1416 | if (skb2 == NULL) | 1435 | if (skb2 == NULL) |
1417 | return -ENOMEM; | 1436 | return -ENOMEM; |
1418 | 1437 | ||
1419 | nlh2 = start_msg(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, | 1438 | nlh2 = start_msg(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, |
1420 | IPSET_CMD_TYPE); | 1439 | IPSET_CMD_TYPE); |
1421 | if (!nlh2) | 1440 | if (!nlh2) |
1422 | goto nlmsg_failure; | 1441 | goto nlmsg_failure; |
1423 | NLA_PUT_U8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); | 1442 | NLA_PUT_U8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); |
1424 | NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, typename); | 1443 | NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, typename); |
1425 | NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, family); | 1444 | NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, family); |
1426 | NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, max); | 1445 | NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, max); |
1427 | NLA_PUT_U8(skb2, IPSET_ATTR_REVISION_MIN, min); | 1446 | NLA_PUT_U8(skb2, IPSET_ATTR_REVISION_MIN, min); |
1428 | nlmsg_end(skb2, nlh2); | 1447 | nlmsg_end(skb2, nlh2); |
1429 | 1448 | ||
1430 | pr_debug("Send TYPE, nlmsg_len: %u\n", nlh2->nlmsg_len); | 1449 | pr_debug("Send TYPE, nlmsg_len: %u\n", nlh2->nlmsg_len); |
1431 | ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | 1450 | ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); |
1432 | if (ret < 0) | 1451 | if (ret < 0) |
1433 | return ret; | 1452 | return ret; |
1434 | 1453 | ||
1435 | return 0; | 1454 | return 0; |
1436 | 1455 | ||
1437 | nla_put_failure: | 1456 | nla_put_failure: |
1438 | nlmsg_cancel(skb2, nlh2); | 1457 | nlmsg_cancel(skb2, nlh2); |
1439 | nlmsg_failure: | 1458 | nlmsg_failure: |
1440 | kfree_skb(skb2); | 1459 | kfree_skb(skb2); |
1441 | return -EMSGSIZE; | 1460 | return -EMSGSIZE; |
1442 | } | 1461 | } |
1443 | 1462 | ||
1444 | /* Get protocol version */ | 1463 | /* Get protocol version */ |
1445 | 1464 | ||
1446 | static const struct nla_policy | 1465 | static const struct nla_policy |
1447 | ip_set_protocol_policy[IPSET_ATTR_CMD_MAX + 1] = { | 1466 | ip_set_protocol_policy[IPSET_ATTR_CMD_MAX + 1] = { |
1448 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, | 1467 | [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, |
1449 | }; | 1468 | }; |
1450 | 1469 | ||
1451 | static int | 1470 | static int |
1452 | ip_set_protocol(struct sock *ctnl, struct sk_buff *skb, | 1471 | ip_set_protocol(struct sock *ctnl, struct sk_buff *skb, |
1453 | const struct nlmsghdr *nlh, | 1472 | const struct nlmsghdr *nlh, |
1454 | const struct nlattr * const attr[]) | 1473 | const struct nlattr * const attr[]) |
1455 | { | 1474 | { |
1456 | struct sk_buff *skb2; | 1475 | struct sk_buff *skb2; |
1457 | struct nlmsghdr *nlh2; | 1476 | struct nlmsghdr *nlh2; |
1458 | int ret = 0; | 1477 | int ret = 0; |
1459 | 1478 | ||
1460 | if (unlikely(attr[IPSET_ATTR_PROTOCOL] == NULL)) | 1479 | if (unlikely(attr[IPSET_ATTR_PROTOCOL] == NULL)) |
1461 | return -IPSET_ERR_PROTOCOL; | 1480 | return -IPSET_ERR_PROTOCOL; |
1462 | 1481 | ||
1463 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1482 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1464 | if (skb2 == NULL) | 1483 | if (skb2 == NULL) |
1465 | return -ENOMEM; | 1484 | return -ENOMEM; |
1466 | 1485 | ||
1467 | nlh2 = start_msg(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, | 1486 | nlh2 = start_msg(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, |
1468 | IPSET_CMD_PROTOCOL); | 1487 | IPSET_CMD_PROTOCOL); |
1469 | if (!nlh2) | 1488 | if (!nlh2) |
1470 | goto nlmsg_failure; | 1489 | goto nlmsg_failure; |
1471 | NLA_PUT_U8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); | 1490 | NLA_PUT_U8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); |
1472 | nlmsg_end(skb2, nlh2); | 1491 | nlmsg_end(skb2, nlh2); |
1473 | 1492 | ||
1474 | ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | 1493 | ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); |
1475 | if (ret < 0) | 1494 | if (ret < 0) |
1476 | return ret; | 1495 | return ret; |
1477 | 1496 | ||
1478 | return 0; | 1497 | return 0; |
1479 | 1498 | ||
1480 | nla_put_failure: | 1499 | nla_put_failure: |
1481 | nlmsg_cancel(skb2, nlh2); | 1500 | nlmsg_cancel(skb2, nlh2); |
1482 | nlmsg_failure: | 1501 | nlmsg_failure: |
1483 | kfree_skb(skb2); | 1502 | kfree_skb(skb2); |
1484 | return -EMSGSIZE; | 1503 | return -EMSGSIZE; |
1485 | } | 1504 | } |
1486 | 1505 | ||
1487 | static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = { | 1506 | static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = { |
1488 | [IPSET_CMD_CREATE] = { | 1507 | [IPSET_CMD_CREATE] = { |
1489 | .call = ip_set_create, | 1508 | .call = ip_set_create, |
1490 | .attr_count = IPSET_ATTR_CMD_MAX, | 1509 | .attr_count = IPSET_ATTR_CMD_MAX, |
1491 | .policy = ip_set_create_policy, | 1510 | .policy = ip_set_create_policy, |
1492 | }, | 1511 | }, |
1493 | [IPSET_CMD_DESTROY] = { | 1512 | [IPSET_CMD_DESTROY] = { |
1494 | .call = ip_set_destroy, | 1513 | .call = ip_set_destroy, |
1495 | .attr_count = IPSET_ATTR_CMD_MAX, | 1514 | .attr_count = IPSET_ATTR_CMD_MAX, |
1496 | .policy = ip_set_setname_policy, | 1515 | .policy = ip_set_setname_policy, |
1497 | }, | 1516 | }, |
1498 | [IPSET_CMD_FLUSH] = { | 1517 | [IPSET_CMD_FLUSH] = { |
1499 | .call = ip_set_flush, | 1518 | .call = ip_set_flush, |
1500 | .attr_count = IPSET_ATTR_CMD_MAX, | 1519 | .attr_count = IPSET_ATTR_CMD_MAX, |
1501 | .policy = ip_set_setname_policy, | 1520 | .policy = ip_set_setname_policy, |
1502 | }, | 1521 | }, |
1503 | [IPSET_CMD_RENAME] = { | 1522 | [IPSET_CMD_RENAME] = { |
1504 | .call = ip_set_rename, | 1523 | .call = ip_set_rename, |
1505 | .attr_count = IPSET_ATTR_CMD_MAX, | 1524 | .attr_count = IPSET_ATTR_CMD_MAX, |
1506 | .policy = ip_set_setname2_policy, | 1525 | .policy = ip_set_setname2_policy, |
1507 | }, | 1526 | }, |
1508 | [IPSET_CMD_SWAP] = { | 1527 | [IPSET_CMD_SWAP] = { |
1509 | .call = ip_set_swap, | 1528 | .call = ip_set_swap, |
1510 | .attr_count = IPSET_ATTR_CMD_MAX, | 1529 | .attr_count = IPSET_ATTR_CMD_MAX, |
1511 | .policy = ip_set_setname2_policy, | 1530 | .policy = ip_set_setname2_policy, |
1512 | }, | 1531 | }, |
1513 | [IPSET_CMD_LIST] = { | 1532 | [IPSET_CMD_LIST] = { |
1514 | .call = ip_set_dump, | 1533 | .call = ip_set_dump, |
1515 | .attr_count = IPSET_ATTR_CMD_MAX, | 1534 | .attr_count = IPSET_ATTR_CMD_MAX, |
1516 | .policy = ip_set_setname_policy, | 1535 | .policy = ip_set_setname_policy, |
1517 | }, | 1536 | }, |
1518 | [IPSET_CMD_SAVE] = { | 1537 | [IPSET_CMD_SAVE] = { |
1519 | .call = ip_set_dump, | 1538 | .call = ip_set_dump, |
1520 | .attr_count = IPSET_ATTR_CMD_MAX, | 1539 | .attr_count = IPSET_ATTR_CMD_MAX, |
1521 | .policy = ip_set_setname_policy, | 1540 | .policy = ip_set_setname_policy, |
1522 | }, | 1541 | }, |
1523 | [IPSET_CMD_ADD] = { | 1542 | [IPSET_CMD_ADD] = { |
1524 | .call = ip_set_uadd, | 1543 | .call = ip_set_uadd, |
1525 | .attr_count = IPSET_ATTR_CMD_MAX, | 1544 | .attr_count = IPSET_ATTR_CMD_MAX, |
1526 | .policy = ip_set_adt_policy, | 1545 | .policy = ip_set_adt_policy, |
1527 | }, | 1546 | }, |
1528 | [IPSET_CMD_DEL] = { | 1547 | [IPSET_CMD_DEL] = { |
1529 | .call = ip_set_udel, | 1548 | .call = ip_set_udel, |
1530 | .attr_count = IPSET_ATTR_CMD_MAX, | 1549 | .attr_count = IPSET_ATTR_CMD_MAX, |
1531 | .policy = ip_set_adt_policy, | 1550 | .policy = ip_set_adt_policy, |
1532 | }, | 1551 | }, |
1533 | [IPSET_CMD_TEST] = { | 1552 | [IPSET_CMD_TEST] = { |
1534 | .call = ip_set_utest, | 1553 | .call = ip_set_utest, |
1535 | .attr_count = IPSET_ATTR_CMD_MAX, | 1554 | .attr_count = IPSET_ATTR_CMD_MAX, |
1536 | .policy = ip_set_adt_policy, | 1555 | .policy = ip_set_adt_policy, |
1537 | }, | 1556 | }, |
1538 | [IPSET_CMD_HEADER] = { | 1557 | [IPSET_CMD_HEADER] = { |
1539 | .call = ip_set_header, | 1558 | .call = ip_set_header, |
1540 | .attr_count = IPSET_ATTR_CMD_MAX, | 1559 | .attr_count = IPSET_ATTR_CMD_MAX, |
1541 | .policy = ip_set_setname_policy, | 1560 | .policy = ip_set_setname_policy, |
1542 | }, | 1561 | }, |
1543 | [IPSET_CMD_TYPE] = { | 1562 | [IPSET_CMD_TYPE] = { |
1544 | .call = ip_set_type, | 1563 | .call = ip_set_type, |
1545 | .attr_count = IPSET_ATTR_CMD_MAX, | 1564 | .attr_count = IPSET_ATTR_CMD_MAX, |
1546 | .policy = ip_set_type_policy, | 1565 | .policy = ip_set_type_policy, |
1547 | }, | 1566 | }, |
1548 | [IPSET_CMD_PROTOCOL] = { | 1567 | [IPSET_CMD_PROTOCOL] = { |
1549 | .call = ip_set_protocol, | 1568 | .call = ip_set_protocol, |
1550 | .attr_count = IPSET_ATTR_CMD_MAX, | 1569 | .attr_count = IPSET_ATTR_CMD_MAX, |
1551 | .policy = ip_set_protocol_policy, | 1570 | .policy = ip_set_protocol_policy, |
1552 | }, | 1571 | }, |
1553 | }; | 1572 | }; |
1554 | 1573 | ||
1555 | static struct nfnetlink_subsystem ip_set_netlink_subsys __read_mostly = { | 1574 | static struct nfnetlink_subsystem ip_set_netlink_subsys __read_mostly = { |
1556 | .name = "ip_set", | 1575 | .name = "ip_set", |
1557 | .subsys_id = NFNL_SUBSYS_IPSET, | 1576 | .subsys_id = NFNL_SUBSYS_IPSET, |
1558 | .cb_count = IPSET_MSG_MAX, | 1577 | .cb_count = IPSET_MSG_MAX, |
1559 | .cb = ip_set_netlink_subsys_cb, | 1578 | .cb = ip_set_netlink_subsys_cb, |
1560 | }; | 1579 | }; |
1561 | 1580 | ||
1562 | /* Interface to iptables/ip6tables */ | 1581 | /* Interface to iptables/ip6tables */ |
1563 | 1582 | ||
1564 | static int | 1583 | static int |
1565 | ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) | 1584 | ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) |
1566 | { | 1585 | { |
1567 | unsigned *op; | 1586 | unsigned *op; |
1568 | void *data; | 1587 | void *data; |
1569 | int copylen = *len, ret = 0; | 1588 | int copylen = *len, ret = 0; |
1570 | 1589 | ||
1571 | if (!capable(CAP_NET_ADMIN)) | 1590 | if (!capable(CAP_NET_ADMIN)) |
1572 | return -EPERM; | 1591 | return -EPERM; |
1573 | if (optval != SO_IP_SET) | 1592 | if (optval != SO_IP_SET) |
1574 | return -EBADF; | 1593 | return -EBADF; |
1575 | if (*len < sizeof(unsigned)) | 1594 | if (*len < sizeof(unsigned)) |
1576 | return -EINVAL; | 1595 | return -EINVAL; |
1577 | 1596 | ||
1578 | data = vmalloc(*len); | 1597 | data = vmalloc(*len); |
1579 | if (!data) | 1598 | if (!data) |
1580 | return -ENOMEM; | 1599 | return -ENOMEM; |
1581 | if (copy_from_user(data, user, *len) != 0) { | 1600 | if (copy_from_user(data, user, *len) != 0) { |
1582 | ret = -EFAULT; | 1601 | ret = -EFAULT; |
1583 | goto done; | 1602 | goto done; |
1584 | } | 1603 | } |
1585 | op = (unsigned *) data; | 1604 | op = (unsigned *) data; |
1586 | 1605 | ||
1587 | if (*op < IP_SET_OP_VERSION) { | 1606 | if (*op < IP_SET_OP_VERSION) { |
1588 | /* Check the version at the beginning of operations */ | 1607 | /* Check the version at the beginning of operations */ |
1589 | struct ip_set_req_version *req_version = data; | 1608 | struct ip_set_req_version *req_version = data; |
1590 | if (req_version->version != IPSET_PROTOCOL) { | 1609 | if (req_version->version != IPSET_PROTOCOL) { |
1591 | ret = -EPROTO; | 1610 | ret = -EPROTO; |
1592 | goto done; | 1611 | goto done; |
1593 | } | 1612 | } |
1594 | } | 1613 | } |
1595 | 1614 | ||
1596 | switch (*op) { | 1615 | switch (*op) { |
1597 | case IP_SET_OP_VERSION: { | 1616 | case IP_SET_OP_VERSION: { |
1598 | struct ip_set_req_version *req_version = data; | 1617 | struct ip_set_req_version *req_version = data; |
1599 | 1618 | ||
1600 | if (*len != sizeof(struct ip_set_req_version)) { | 1619 | if (*len != sizeof(struct ip_set_req_version)) { |
1601 | ret = -EINVAL; | 1620 | ret = -EINVAL; |
1602 | goto done; | 1621 | goto done; |
1603 | } | 1622 | } |
1604 | 1623 | ||
1605 | req_version->version = IPSET_PROTOCOL; | 1624 | req_version->version = IPSET_PROTOCOL; |
1606 | ret = copy_to_user(user, req_version, | 1625 | ret = copy_to_user(user, req_version, |
1607 | sizeof(struct ip_set_req_version)); | 1626 | sizeof(struct ip_set_req_version)); |
1608 | goto done; | 1627 | goto done; |
1609 | } | 1628 | } |
1610 | case IP_SET_OP_GET_BYNAME: { | 1629 | case IP_SET_OP_GET_BYNAME: { |
1611 | struct ip_set_req_get_set *req_get = data; | 1630 | struct ip_set_req_get_set *req_get = data; |
1612 | 1631 | ||
1613 | if (*len != sizeof(struct ip_set_req_get_set)) { | 1632 | if (*len != sizeof(struct ip_set_req_get_set)) { |
1614 | ret = -EINVAL; | 1633 | ret = -EINVAL; |
1615 | goto done; | 1634 | goto done; |
1616 | } | 1635 | } |
1617 | req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0'; | 1636 | req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0'; |
1618 | nfnl_lock(); | 1637 | nfnl_lock(); |
1619 | req_get->set.index = find_set_id(req_get->set.name); | 1638 | req_get->set.index = find_set_id(req_get->set.name); |
1620 | nfnl_unlock(); | 1639 | nfnl_unlock(); |
1621 | goto copy; | 1640 | goto copy; |
1622 | } | 1641 | } |
1623 | case IP_SET_OP_GET_BYINDEX: { | 1642 | case IP_SET_OP_GET_BYINDEX: { |
1624 | struct ip_set_req_get_set *req_get = data; | 1643 | struct ip_set_req_get_set *req_get = data; |
1625 | 1644 | ||
1626 | if (*len != sizeof(struct ip_set_req_get_set) || | 1645 | if (*len != sizeof(struct ip_set_req_get_set) || |
1627 | req_get->set.index >= ip_set_max) { | 1646 | req_get->set.index >= ip_set_max) { |
1628 | ret = -EINVAL; | 1647 | ret = -EINVAL; |
1629 | goto done; | 1648 | goto done; |
1630 | } | 1649 | } |
1631 | nfnl_lock(); | 1650 | nfnl_lock(); |
1632 | strncpy(req_get->set.name, | 1651 | strncpy(req_get->set.name, |
1633 | ip_set_list[req_get->set.index] | 1652 | ip_set_list[req_get->set.index] |
1634 | ? ip_set_list[req_get->set.index]->name : "", | 1653 | ? ip_set_list[req_get->set.index]->name : "", |
1635 | IPSET_MAXNAMELEN); | 1654 | IPSET_MAXNAMELEN); |
1636 | nfnl_unlock(); | 1655 | nfnl_unlock(); |
1637 | goto copy; | 1656 | goto copy; |
1638 | } | 1657 | } |
1639 | default: | 1658 | default: |
1640 | ret = -EBADMSG; | 1659 | ret = -EBADMSG; |
1641 | goto done; | 1660 | goto done; |
1642 | } /* end of switch(op) */ | 1661 | } /* end of switch(op) */ |
1643 | 1662 | ||
1644 | copy: | 1663 | copy: |
1645 | ret = copy_to_user(user, data, copylen); | 1664 | ret = copy_to_user(user, data, copylen); |
1646 | 1665 | ||
1647 | done: | 1666 | done: |
1648 | vfree(data); | 1667 | vfree(data); |
1649 | if (ret > 0) | 1668 | if (ret > 0) |
1650 | ret = 0; | 1669 | ret = 0; |
1651 | return ret; | 1670 | return ret; |
1652 | } | 1671 | } |
1653 | 1672 | ||
1654 | static struct nf_sockopt_ops so_set __read_mostly = { | 1673 | static struct nf_sockopt_ops so_set __read_mostly = { |
1655 | .pf = PF_INET, | 1674 | .pf = PF_INET, |
1656 | .get_optmin = SO_IP_SET, | 1675 | .get_optmin = SO_IP_SET, |
1657 | .get_optmax = SO_IP_SET + 1, | 1676 | .get_optmax = SO_IP_SET + 1, |
1658 | .get = &ip_set_sockfn_get, | 1677 | .get = &ip_set_sockfn_get, |
1659 | .owner = THIS_MODULE, | 1678 | .owner = THIS_MODULE, |
1660 | }; | 1679 | }; |
1661 | 1680 | ||
1662 | static int __init | 1681 | static int __init |
1663 | ip_set_init(void) | 1682 | ip_set_init(void) |
1664 | { | 1683 | { |
1665 | int ret; | 1684 | int ret; |
1666 | 1685 | ||
1667 | if (max_sets) | 1686 | if (max_sets) |
1668 | ip_set_max = max_sets; | 1687 | ip_set_max = max_sets; |
1669 | if (ip_set_max >= IPSET_INVALID_ID) | 1688 | if (ip_set_max >= IPSET_INVALID_ID) |
1670 | ip_set_max = IPSET_INVALID_ID - 1; | 1689 | ip_set_max = IPSET_INVALID_ID - 1; |
1671 | 1690 | ||
1672 | ip_set_list = kzalloc(sizeof(struct ip_set *) * ip_set_max, | 1691 | ip_set_list = kzalloc(sizeof(struct ip_set *) * ip_set_max, |
1673 | GFP_KERNEL); | 1692 | GFP_KERNEL); |
1674 | if (!ip_set_list) { | 1693 | if (!ip_set_list) { |
1675 | pr_err("ip_set: Unable to create ip_set_list\n"); | 1694 | pr_err("ip_set: Unable to create ip_set_list\n"); |
1676 | return -ENOMEM; | 1695 | return -ENOMEM; |
1677 | } | 1696 | } |
1678 | 1697 | ||
1679 | ret = nfnetlink_subsys_register(&ip_set_netlink_subsys); | 1698 | ret = nfnetlink_subsys_register(&ip_set_netlink_subsys); |
1680 | if (ret != 0) { | 1699 | if (ret != 0) { |
1681 | pr_err("ip_set: cannot register with nfnetlink.\n"); | 1700 | pr_err("ip_set: cannot register with nfnetlink.\n"); |
1682 | kfree(ip_set_list); | 1701 | kfree(ip_set_list); |
1683 | return ret; | 1702 | return ret; |
1684 | } | 1703 | } |
1685 | ret = nf_register_sockopt(&so_set); | 1704 | ret = nf_register_sockopt(&so_set); |
1686 | if (ret != 0) { | 1705 | if (ret != 0) { |
1687 | pr_err("SO_SET registry failed: %d\n", ret); | 1706 | pr_err("SO_SET registry failed: %d\n", ret); |
1688 | nfnetlink_subsys_unregister(&ip_set_netlink_subsys); | 1707 | nfnetlink_subsys_unregister(&ip_set_netlink_subsys); |
1689 | kfree(ip_set_list); | 1708 | kfree(ip_set_list); |
1690 | return ret; | 1709 | return ret; |
1691 | } | 1710 | } |
1692 | 1711 | ||
1693 | pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL); | 1712 | pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL); |
1694 | return 0; | 1713 | return 0; |
1695 | } | 1714 | } |
1696 | 1715 | ||
1697 | static void __exit | 1716 | static void __exit |
1698 | ip_set_fini(void) | 1717 | ip_set_fini(void) |
1699 | { | 1718 | { |
1700 | /* There can't be any existing set */ | 1719 | /* There can't be any existing set */ |
1701 | nf_unregister_sockopt(&so_set); | 1720 | nf_unregister_sockopt(&so_set); |
1702 | nfnetlink_subsys_unregister(&ip_set_netlink_subsys); | 1721 | nfnetlink_subsys_unregister(&ip_set_netlink_subsys); |
1703 | kfree(ip_set_list); | 1722 | kfree(ip_set_list); |
1704 | pr_debug("these are the famous last words\n"); | 1723 | pr_debug("these are the famous last words\n"); |
1705 | } | 1724 | } |