📄 vqp.c
字号:
/* * vqp.c Functions to send/receive VQP packets. * * Version: $Id: vqp.c,v 1.4 2008/01/05 17:58:44 nbk Exp $ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2007 Alan DeKok <aland@deployingradius.com> */#include <freeradius-devel/ident.h>RCSID("$Id: vqp.c,v 1.4 2008/01/05 17:58:44 nbk Exp $");#include <freeradius-devel/libradius.h>#include <freeradius-devel/udpfromto.h>#include <freeradius-devel/vqp.h>#ifdef WITH_VMPS/* * http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/tcpdump/print-vqp.c * * Some of how it works: * * http://www.hackingciscoexposed.com/pdf/chapter12.pdf * * VLAN Query Protocol (VQP) * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Version | Opcode | Response Code | Data Count | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Transaction ID | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type (1) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Length | Data / * / / * / / * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type (n) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Length | Data / * / / * / / * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * VQP is layered over UDP. The default destination port is 1589. * */#define VQP_HDR_LEN (8)#define VQP_VERSION (1)#define VQP_MAX_ATTRIBUTES (12)/* * Wrapper for sendto which handles sendfromto, IPv6, and all * possible combinations. * * FIXME: This is just a copy of rad_sendto(). * Duplicate code is bad. */static int vqp_sendto(int sockfd, void *data, size_t data_len, int flags, fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, int dst_port){ struct sockaddr_storage dst; socklen_t sizeof_dst = sizeof(dst);#ifdef WITH_UDPFROMTO struct sockaddr_storage src; socklen_t sizeof_src = sizeof(src); memset(&src, 0, sizeof(src));#endif memset(&dst, 0, sizeof(dst)); /* * IPv4 is supported. */ if (dst_ipaddr->af == AF_INET) { struct sockaddr_in *s4; s4 = (struct sockaddr_in *)&dst; sizeof_dst = sizeof(struct sockaddr_in); s4->sin_family = AF_INET; s4->sin_addr = dst_ipaddr->ipaddr.ip4addr; s4->sin_port = htons(dst_port);#ifdef WITH_UDPFROMTO s4 = (struct sockaddr_in *)&src; sizeof_src = sizeof(struct sockaddr_in); s4->sin_family = AF_INET; s4->sin_addr = src_ipaddr->ipaddr.ip4addr;#endif /* * IPv6 MAY be supported. */#ifdef HAVE_STRUCT_SOCKADDR_IN6 } else if (dst_ipaddr->af == AF_INET6) { struct sockaddr_in6 *s6; s6 = (struct sockaddr_in6 *)&dst; sizeof_dst = sizeof(struct sockaddr_in6); s6->sin6_family = AF_INET6; s6->sin6_addr = dst_ipaddr->ipaddr.ip6addr; s6->sin6_port = htons(dst_port);#ifdef WITH_UDPFROMTO return -1; /* UDPFROMTO && IPv6 are not supported */#if 0 s6 = (struct sockaddr_in6 *)&src; sizeof_src = sizeof(struct sockaddr_in6); s6->sin6_family = AF_INET6; s6->sin6_addr = src_ipaddr->ipaddr.ip6addr;#endif /* #if 0 */#endif /* WITH_UDPFROMTO */#endif /* HAVE_STRUCT_SOCKADDR_IN6 */ } else return -1; /* Unknown address family, Die Die Die! */#ifdef WITH_UDPFROMTO /* * Only IPv4 is supported for udpfromto. * * And if they don't specify a source IP address, don't * use udpfromto. */ if ((dst_ipaddr->af == AF_INET) || (src_ipaddr->af != AF_UNSPEC)) { return sendfromto(sockfd, data, data_len, flags, (struct sockaddr *)&src, sizeof_src, (struct sockaddr *)&dst, sizeof_dst); }#else src_ipaddr = src_ipaddr; /* -Wunused */#endif /* * No udpfromto, OR an IPv6 socket, fail gracefully. */ return sendto(sockfd, data, data_len, flags, (struct sockaddr *)&dst, sizeof_dst);}/* * Wrapper for recvfrom, which handles recvfromto, IPv6, and all * possible combinations. * * FIXME: This is copied from rad_recvfrom, with minor edits. */static ssize_t vqp_recvfrom(int sockfd, uint8_t **pbuf, int flags, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_t *dst_ipaddr, uint16_t *dst_port){ struct sockaddr_storage src; struct sockaddr_storage dst; socklen_t sizeof_src = sizeof(src); socklen_t sizeof_dst = sizeof(dst); ssize_t data_len; uint8_t header[4]; void *buf; size_t len; memset(&src, 0, sizeof_src); memset(&dst, 0, sizeof_dst); /* * Get address family, etc. first, so we know if we * need to do udpfromto. * * FIXME: udpfromto also does this, but it's not * a critical problem. */ if (getsockname(sockfd, (struct sockaddr *)&dst, &sizeof_dst) < 0) return -1; /* * Read the length of the packet, from the packet. * This lets us allocate the buffer to use for * reading the rest of the packet. */ data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK, (struct sockaddr *)&src, &sizeof_src); if (data_len < 0) return -1; /* * Too little data is available, discard the packet. */ if (data_len < 4) { recvfrom(sockfd, header, sizeof(header), flags, (struct sockaddr *)&src, &sizeof_src); return 0; /* * Invalid version, packet type, or too many * attributes. Die. */ } else if ((header[0] != VQP_VERSION) || (header[1] < 1) || (header[1] > 4) || (header[3] > VQP_MAX_ATTRIBUTES)) { recvfrom(sockfd, header, sizeof(header), flags, (struct sockaddr *)&src, &sizeof_src); return 0; } else { /* we got 4 bytes of data. */ /* * We don't care about the contents for now... */#if 0 /* * How many attributes are in the packet. */ len = header[3]; if ((header[1] == 1) || (header[1] == 3)) { if (len != VQP_MAX_ATTRIBUTES) { recvfrom(sockfd, header, sizeof(header), 0, (struct sockaddr *)&src, &sizeof_src); return 0; } /* * Maximum length we support. */ len = (12 * (4 + 4 + 253)); } else { if (len != 2) { recvfrom(sockfd, header, sizeof(header), 0, (struct sockaddr *)&src, &sizeof_src); return 0; } /* * Maximum length we support. */ len = (12 * (4 + 4 + 253)); }#endif } /* * For now, be generous. */ len = (12 * (4 + 4 + 253)); buf = malloc(len); if (!buf) return -1; /* * Receive the packet. The OS will discard any data in the * packet after "len" bytes. */#ifdef WITH_UDPFROMTO if (dst.ss_family == AF_INET) { data_len = recvfromto(sockfd, buf, len, flags, (struct sockaddr *)&src, &sizeof_src, (struct sockaddr *)&dst, &sizeof_dst); } else#endif /* * No udpfromto, OR an IPv6 socket. Fail gracefully. */ data_len = recvfrom(sockfd, buf, len, flags, (struct sockaddr *)&src, &sizeof_src); if (data_len < 0) { free(buf); return data_len; } /* * Check address families, and update src/dst ports, etc. */ if (src.ss_family == AF_INET) { struct sockaddr_in *s4; s4 = (struct sockaddr_in *)&src; src_ipaddr->af = AF_INET; src_ipaddr->ipaddr.ip4addr = s4->sin_addr; *src_port = ntohs(s4->sin_port); s4 = (struct sockaddr_in *)&dst; dst_ipaddr->af = AF_INET; dst_ipaddr->ipaddr.ip4addr = s4->sin_addr; *dst_port = ntohs(s4->sin_port);#ifdef HAVE_STRUCT_SOCKADDR_IN6 } else if (src.ss_family == AF_INET6) { struct sockaddr_in6 *s6; s6 = (struct sockaddr_in6 *)&src; src_ipaddr->af = AF_INET6; src_ipaddr->ipaddr.ip6addr = s6->sin6_addr; *src_port = ntohs(s6->sin6_port); s6 = (struct sockaddr_in6 *)&dst; dst_ipaddr->af = AF_INET6; dst_ipaddr->ipaddr.ip6addr = s6->sin6_addr; *dst_port = ntohs(s6->sin6_port);#endif } else { free(buf); return -1; /* Unknown address family, Die Die Die! */ } /* * Different address families should never happen. */ if (src.ss_family != dst.ss_family) { free(buf); return -1; } /* * Tell the caller about the data */ *pbuf = buf; return data_len;}RADIUS_PACKET *vqp_recv(int sockfd){ uint8_t *ptr; ssize_t length; uint32_t id; RADIUS_PACKET *packet; /* * Allocate the new request data structure */ if ((packet = malloc(sizeof(*packet))) == NULL) { librad_log("out of memory"); return NULL; } memset(packet, 0, sizeof(*packet)); packet->data_len = vqp_recvfrom(sockfd, &packet->data, 0, &packet->src_ipaddr, &packet->src_port, &packet->dst_ipaddr, &packet->dst_port); /* * Check for socket errors. */ if (packet->data_len < 0) { librad_log("Error receiving packet: %s", strerror(errno)); /* packet->data is NULL */ free(packet); return NULL; } /* * We can only receive packets formatted in a way we * expect. However, we accept MORE attributes in a * packet than normal implementations may send. */ if (packet->data_len < VQP_HDR_LEN) { librad_log("VQP packet is too short"); rad_free(&packet);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -