1/* 2 * (C) 2009 by Pablo Neira Ayuso <pablo@netfilter.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 10#include <stdlib.h> 11#include <unistd.h> 12#include <net/if.h> 13#include <string.h> 14#include <sys/ioctl.h> 15#include <netinet/in.h> 16#include <errno.h> 17 18#include "conntrackd.h" 19#include "channel.h" 20#include "network.h" 21#include "queue.h" 22 23static struct channel_ops *ops[CHANNEL_MAX]; 24extern struct channel_ops channel_mcast; 25extern struct channel_ops channel_udp; 26extern struct channel_ops channel_tcp; 27 28static struct queue *errorq; 29 30int channel_init(void) 31{ 32 ops[CHANNEL_MCAST] = &channel_mcast; 33 ops[CHANNEL_UDP] = &channel_udp; 34 ops[CHANNEL_TCP] = &channel_tcp; 35 36 errorq = queue_create("errorq", CONFIG(channelc).error_queue_length, 0); 37 if (errorq == NULL) { 38 return -1; 39 } 40 return 0; 41} 42 43void channel_end(void) 44{ 45 queue_destroy(errorq); 46} 47 48struct channel_buffer { 49 char *data; 50 int size; 51 int len; 52}; 53 54static struct channel_buffer * 55channel_buffer_open(int mtu, int headersiz) 56{ 57 struct channel_buffer *b; 58 59 b = calloc(sizeof(struct channel_buffer), 1); 60 if (b == NULL) 61 return NULL; 62 63 b->size = mtu - headersiz; 64 65 b->data = malloc(b->size); 66 if (b->data == NULL) { 67 free(b); 68 return NULL; 69 } 70 return b; 71} 72 73static void 74channel_buffer_close(struct channel_buffer *b) 75{ 76 if (b == NULL) 77 return; 78 79 free(b->data); 80 free(b); 81} 82 83struct channel * 84channel_open(struct channel_conf *cfg) 85{ 86 struct channel *c; 87 struct ifreq ifr; 88 int fd; 89 90 if (cfg->channel_type >= CHANNEL_MAX) 91 return NULL; 92 if (!cfg->channel_ifname[0]) 93 return NULL; 94 if (cfg->channel_flags >= CHANNEL_F_MAX) 95 return NULL; 96 97 c = calloc(sizeof(struct channel), 1); 98 if (c == NULL) 99 return NULL; 100 101 c->channel_type = cfg->channel_type; 102 103 fd = socket(AF_INET, SOCK_DGRAM, 0); 104 if (fd == -1) { 105 free(c); 106 return NULL; 107 } 108 strncpy(ifr.ifr_name, cfg->channel_ifname, sizeof(ifr.ifr_name)); 109 110 if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) { 111 free(c); 112 return NULL; 113 } 114 close(fd); 115 c->channel_ifmtu = ifr.ifr_mtu; 116 117 c->channel_ifindex = if_nametoindex(cfg->channel_ifname); 118 if (c->channel_ifindex == 0) { 119 free(c); 120 return NULL; 121 } 122 c->ops = ops[cfg->channel_type]; 123 124 if (cfg->channel_flags & CHANNEL_F_BUFFERED) { 125 c->buffer = channel_buffer_open(c->channel_ifmtu, 126 c->ops->headersiz); 127 if (c->buffer == NULL) { 128 free(c); 129 return NULL; 130 } 131 } 132 c->channel_flags = cfg->channel_flags; 133 134 c->data = c->ops->open(&cfg->u); 135 if (c->data == NULL) { 136 channel_buffer_close(c->buffer); 137 free(c); 138 return NULL; 139 } 140 return c; 141} 142 143void 144channel_close(struct channel *c) 145{ 146 c->ops->close(c->data); 147 if (c->channel_flags & CHANNEL_F_BUFFERED) 148 channel_buffer_close(c->buffer); 149 free(c); 150} 151 152struct channel_error { 153 char *data; 154 int len; 155}; 156 157static void channel_enqueue_errors(struct channel *c) 158{ 159 struct queue_object *qobj; 160 struct channel_error *error; 161 162 qobj = queue_object_new(Q_ELEM_ERR, sizeof(struct channel_error)); 163 if (qobj == NULL) 164 return; 165 166 error = (struct channel_error *)qobj->data; 167 error->len = c->buffer->len; 168 169 error->data = malloc(c->buffer->len); 170 if (error->data == NULL) { 171 queue_object_free(qobj); 172 return; 173 } 174 memcpy(error->data, c->buffer->data, c->buffer->len); 175 if (queue_add(errorq, &qobj->qnode) < 0) { 176 if (errno == ENOSPC) { 177 struct queue_node *tail; 178 struct channel_error *tmp; 179 180 tail = queue_del_head(errorq); 181 tmp = queue_node_data(tail); 182 free(tmp->data); 183 queue_object_free((struct queue_object *)tail); 184 185 queue_add(errorq, &qobj->qnode); 186 } 187 } 188} 189 190static int channel_handle_error_step(struct queue_node *n, const void *data2) 191{ 192 struct channel_error *error; 193 const struct channel *c = data2; 194 int ret; 195 196 error = queue_node_data(n); 197 ret = c->ops->send(c->data, error->data, error->len); 198 if (ret != -1) { 199 /* Success. Delete it from the error queue. */ 200 queue_del(n); 201 free(error->data); 202 queue_object_free((struct queue_object *)n); 203 } else { 204 /* We failed to deliver, give up now, try later. */ 205 return 1; 206 } 207 return 0; 208} 209 210static int channel_handle_errors(struct channel *c) 211{ 212 /* there are pending errors that we have to handle. */ 213 if (c->channel_flags & CHANNEL_F_ERRORS && queue_len(errorq) > 0) { 214 queue_iterate(errorq, c, channel_handle_error_step); 215 return queue_len(errorq) > 0; 216 } 217 return 0; 218} 219 220int channel_send(struct channel *c, const struct nethdr *net) 221{ 222 int ret = 0, len = ntohs(net->len), pending_errors; 223 224 pending_errors = channel_handle_errors(c); 225 226 if (!(c->channel_flags & CHANNEL_F_BUFFERED)) { 227 c->ops->send(c->data, net, len); 228 return 1; 229 } 230retry: 231 if (c->buffer->len + len < c->buffer->size) { 232 memcpy(c->buffer->data + c->buffer->len, net, len); 233 c->buffer->len += len; 234 } else { 235 /* We've got pending packets to deliver, enqueue this 236 * packet to avoid possible re-ordering. */ 237 if (pending_errors) { 238 channel_enqueue_errors(c); 239 } else { 240 ret = c->ops->send(c->data, c->buffer->data, 241 c->buffer->len); 242 if (ret == -1 && 243 (c->channel_flags & CHANNEL_F_ERRORS)) { 244 /* Give it another chance to deliver. */ 245 channel_enqueue_errors(c); 246 } 247 } 248 ret = 1; 249 c->buffer->len = 0; 250 goto retry; 251 } 252 return ret; 253} 254 255int channel_send_flush(struct channel *c) 256{ 257 int ret, pending_errors; 258 259 pending_errors = channel_handle_errors(c); 260 261 if (!(c->channel_flags & CHANNEL_F_BUFFERED) || c->buffer->len == 0) 262 return 0; 263 264 /* We still have pending errors to deliver, avoid any re-ordering. */ 265 if (pending_errors) { 266 channel_enqueue_errors(c); 267 } else { 268 ret = c->ops->send(c->data, c->buffer->data, c->buffer->len); 269 if (ret == -1 && (c->channel_flags & CHANNEL_F_ERRORS)) { 270 /* Give it another chance to deliver it. */ 271 channel_enqueue_errors(c); 272 } 273 } 274 c->buffer->len = 0; 275 return 1; 276} 277 278int channel_recv(struct channel *c, char *buf, int size) 279{ 280 return c->ops->recv(c->data, buf, size); 281} 282 283int channel_get_fd(struct channel *c) 284{ 285 return c->ops->get_fd(c->data); 286} 287 288void channel_stats(struct channel *c, int fd) 289{ 290 return c->ops->stats(c, fd); 291} 292 293void channel_stats_extended(struct channel *c, int active, 294 struct nlif_handle *h, int fd) 295{ 296 return c->ops->stats_extended(c, active, h, fd); 297} 298 299int channel_accept_isset(struct channel *c, fd_set *readfds) 300{ 301 return c->ops->accept_isset(c, readfds); 302} 303 304int channel_isset(struct channel *c, fd_set *readfds) 305{ 306 return c->ops->isset(c, readfds); 307} 308 309int channel_accept(struct channel *c) 310{ 311 return c->ops->accept(c); 312} 313 314int channel_type(struct channel *c) 315{ 316 return c->ops->type; 317} 318