1 /* 2 * lib/netfilter/queue.c Netfilter Queue 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2007, 2008 Patrick McHardy <kaber (at) trash.net> 10 */ 11 12 /** 13 * @ingroup nfnl 14 * @defgroup queue Queue 15 * @brief 16 * @{ 17 */ 18 19 #include <sys/types.h> 20 #include <linux/netfilter/nfnetlink_queue.h> 21 22 #include <netlink-local.h> 23 #include <netlink/attr.h> 24 #include <netlink/netfilter/nfnl.h> 25 #include <netlink/netfilter/queue.h> 26 27 struct nl_sock *nfnl_queue_socket_alloc(void) 28 { 29 struct nl_sock *nlsk; 30 31 nlsk = nl_socket_alloc(); 32 if (nlsk) 33 nl_socket_disable_auto_ack(nlsk); 34 return nlsk; 35 } 36 37 static int send_queue_request(struct nl_sock *sk, struct nl_msg *msg) 38 { 39 int err; 40 41 err = nl_send_auto_complete(sk, msg); 42 nlmsg_free(msg); 43 if (err < 0) 44 return err; 45 46 return wait_for_ack(sk); 47 } 48 49 /** 50 * @name Queue Commands 51 * @{ 52 */ 53 54 static int build_queue_cmd_request(uint8_t family, uint16_t queuenum, 55 uint8_t command, struct nl_msg **result) 56 { 57 struct nl_msg *msg; 58 struct nfqnl_msg_config_cmd cmd; 59 60 msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0, 61 family, queuenum); 62 if (msg == NULL) 63 return -NLE_NOMEM; 64 65 cmd.pf = htons(family); 66 cmd._pad = 0; 67 cmd.command = command; 68 if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0) 69 goto nla_put_failure; 70 71 *result = msg; 72 return 0; 73 74 nla_put_failure: 75 nlmsg_free(msg); 76 return -NLE_MSGSIZE; 77 } 78 79 int nfnl_queue_build_pf_bind(uint8_t pf, struct nl_msg **result) 80 { 81 return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_BIND, result); 82 } 83 84 int nfnl_queue_pf_bind(struct nl_sock *nlh, uint8_t pf) 85 { 86 struct nl_msg *msg; 87 int err; 88 89 if ((err = nfnl_queue_build_pf_bind(pf, &msg)) < 0) 90 return err; 91 92 return send_queue_request(nlh, msg); 93 } 94 95 int nfnl_queue_build_pf_unbind(uint8_t pf, struct nl_msg **result) 96 { 97 return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_UNBIND, result); 98 } 99 100 int nfnl_queue_pf_unbind(struct nl_sock *nlh, uint8_t pf) 101 { 102 struct nl_msg *msg; 103 int err; 104 105 if ((err = nfnl_queue_build_pf_unbind(pf, &msg)) < 0) 106 return err; 107 108 return send_queue_request(nlh, msg); 109 } 110 111 static int nfnl_queue_build_request(const struct nfnl_queue *queue, 112 struct nl_msg **result) 113 { 114 struct nl_msg *msg; 115 116 if (!nfnl_queue_test_group(queue)) 117 return -NLE_MISSING_ATTR; 118 119 msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0, 120 0, nfnl_queue_get_group(queue)); 121 if (msg == NULL) 122 return -NLE_NOMEM; 123 124 if (nfnl_queue_test_maxlen(queue) && 125 nla_put_u32(msg, NFQA_CFG_QUEUE_MAXLEN, 126 htonl(nfnl_queue_get_maxlen(queue))) < 0) 127 goto nla_put_failure; 128 129 /* This sucks, the nfnetlink_queue interface always expects both 130 * parameters to be present. Needs to be done properly. 131 */ 132 if (nfnl_queue_test_copy_mode(queue)) { 133 struct nfqnl_msg_config_params params; 134 135 switch (nfnl_queue_get_copy_mode(queue)) { 136 case NFNL_QUEUE_COPY_NONE: 137 params.copy_mode = NFQNL_COPY_NONE; 138 break; 139 case NFNL_QUEUE_COPY_META: 140 params.copy_mode = NFQNL_COPY_META; 141 break; 142 case NFNL_QUEUE_COPY_PACKET: 143 params.copy_mode = NFQNL_COPY_PACKET; 144 break; 145 } 146 params.copy_range = htonl(nfnl_queue_get_copy_range(queue)); 147 148 if (nla_put(msg, NFQA_CFG_PARAMS, sizeof(params), ¶ms) < 0) 149 goto nla_put_failure; 150 } 151 152 *result = msg; 153 return 0; 154 155 nla_put_failure: 156 nlmsg_free(msg); 157 return -NLE_MSGSIZE; 158 } 159 160 int nfnl_queue_build_create_request(const struct nfnl_queue *queue, 161 struct nl_msg **result) 162 { 163 struct nfqnl_msg_config_cmd cmd; 164 int err; 165 166 if ((err = nfnl_queue_build_request(queue, result)) < 0) 167 return err; 168 169 cmd.pf = 0; 170 cmd._pad = 0; 171 cmd.command = NFQNL_CFG_CMD_BIND; 172 173 NLA_PUT(*result, NFQA_CFG_CMD, sizeof(cmd), &cmd); 174 175 return 0; 176 177 nla_put_failure: 178 nlmsg_free(*result); 179 return -NLE_MSGSIZE; 180 } 181 182 int nfnl_queue_create(struct nl_sock *nlh, const struct nfnl_queue *queue) 183 { 184 struct nl_msg *msg; 185 int err; 186 187 if ((err = nfnl_queue_build_create_request(queue, &msg)) < 0) 188 return err; 189 190 return send_queue_request(nlh, msg); 191 } 192 193 int nfnl_queue_build_change_request(const struct nfnl_queue *queue, 194 struct nl_msg **result) 195 { 196 return nfnl_queue_build_request(queue, result); 197 } 198 199 int nfnl_queue_change(struct nl_sock *nlh, const struct nfnl_queue *queue) 200 { 201 struct nl_msg *msg; 202 int err; 203 204 if ((err = nfnl_queue_build_change_request(queue, &msg)) < 0) 205 return err; 206 207 return send_queue_request(nlh, msg); 208 } 209 210 int nfnl_queue_build_delete_request(const struct nfnl_queue *queue, 211 struct nl_msg **result) 212 { 213 if (!nfnl_queue_test_group(queue)) 214 return -NLE_MISSING_ATTR; 215 216 return build_queue_cmd_request(0, nfnl_queue_get_group(queue), 217 NFQNL_CFG_CMD_UNBIND, result); 218 } 219 220 int nfnl_queue_delete(struct nl_sock *nlh, const struct nfnl_queue *queue) 221 { 222 struct nl_msg *msg; 223 int err; 224 225 if ((err = nfnl_queue_build_delete_request(queue, &msg)) < 0) 226 return err; 227 228 return send_queue_request(nlh, msg); 229 } 230 231 /** @} */ 232 233 static struct nl_cache_ops nfnl_queue_ops = { 234 .co_name = "netfilter/queue", 235 .co_obj_ops = &queue_obj_ops, 236 .co_msgtypes = { 237 END_OF_MSGTYPES_LIST, 238 }, 239 }; 240 241 static void __init nfnl_queue_init(void) 242 { 243 nl_cache_mngt_register(&nfnl_queue_ops); 244 } 245 246 static void __exit nfnl_queue_exit(void) 247 { 248 nl_cache_mngt_unregister(&nfnl_queue_ops); 249 } 250 251 /** @} */ 252