trans_udp.c revision 133211
1184610Salfred/* 2184610Salfred * Copyright (c) 2003 3184610Salfred * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4184610Salfred * All rights reserved. 5184610Salfred * 6184610Salfred * Author: Harti Brandt <harti@freebsd.org> 7184610Salfred * 8184610Salfred * Redistribution and use in source and binary forms, with or without 9184610Salfred * modification, are permitted provided that the following conditions 10184610Salfred * are met: 11184610Salfred * 1. Redistributions of source code must retain the above copyright 12184610Salfred * notice, this list of conditions and the following disclaimer. 13184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 14184610Salfred * notice, this list of conditions and the following disclaimer in the 15184610Salfred * documentation and/or other materials provided with the distribution. 16184610Salfred * 17184610Salfred * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26188417Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27188417Sthompsa * SUCH DAMAGE. 28188417Sthompsa * 29188417Sthompsa * $Begemot: bsnmp/snmpd/trans_udp.c,v 1.4 2004/08/06 08:47:16 brandt Exp $ 30188417Sthompsa * 31188417Sthompsa * UDP transport 32188417Sthompsa */ 33188417Sthompsa#include <sys/types.h> 34188417Sthompsa 35188417Sthompsa#include <stdlib.h> 36188417Sthompsa#include <syslog.h> 37188417Sthompsa#include <string.h> 38188417Sthompsa#include <errno.h> 39188417Sthompsa#include <unistd.h> 40188417Sthompsa 41188417Sthompsa#include <netinet/in.h> 42188417Sthompsa#include <arpa/inet.h> 43188417Sthompsa 44188417Sthompsa#include "snmpmod.h" 45188417Sthompsa#include "snmpd.h" 46188417Sthompsa#include "trans_udp.h" 47188417Sthompsa#include "tree.h" 48188417Sthompsa#include "oid.h" 49188417Sthompsa 50188417Sthompsastatic int udp_start(void); 51184610Salfredstatic int udp_stop(int); 52184610Salfredstatic void udp_close_port(struct tport *); 53184610Salfredstatic int udp_init_port(struct tport *); 54184610Salfredstatic ssize_t udp_send(struct tport *, const u_char *, size_t, 55188417Sthompsa const struct sockaddr *, size_t); 56188417Sthompsa 57188417Sthompsa/* exported */ 58188417Sthompsaconst struct transport_def udp_trans = { 59188417Sthompsa "udp", 60188417Sthompsa OIDX_begemotSnmpdTransUdp, 61188417Sthompsa udp_start, 62188417Sthompsa udp_stop, 63188417Sthompsa udp_close_port, 64188417Sthompsa udp_init_port, 65188417Sthompsa udp_send 66188417Sthompsa}; 67188417Sthompsastatic struct transport *my_trans; 68188417Sthompsa 69188417Sthompsastatic int 70188417Sthompsaudp_start(void) 71188417Sthompsa{ 72188417Sthompsa return (trans_register(&udp_trans, &my_trans)); 73188417Sthompsa} 74188417Sthompsa 75188417Sthompsastatic int 76188417Sthompsaudp_stop(int force __unused) 77188417Sthompsa{ 78188417Sthompsa if (my_trans != NULL) 79188417Sthompsa if (trans_unregister(my_trans) != 0) 80188417Sthompsa return (SNMP_ERR_GENERR); 81188417Sthompsa return (SNMP_ERR_NOERROR); 82188417Sthompsa} 83188417Sthompsa 84188417Sthompsa/* 85188417Sthompsa * A UDP port is ready 86188417Sthompsa */ 87188417Sthompsastatic void 88188417Sthompsaudp_input(int fd __unused, void *udata) 89188417Sthompsa{ 90188417Sthompsa struct udp_port *p = udata; 91188417Sthompsa 92188417Sthompsa p->input.peerlen = sizeof(p->ret); 93188417Sthompsa snmpd_input(&p->input, &p->tport); 94188417Sthompsa} 95188417Sthompsa 96188417Sthompsa/* 97188417Sthompsa * Create a UDP socket and bind it to the given port 98188417Sthompsa */ 99188417Sthompsastatic int 100188417Sthompsaudp_init_port(struct tport *tp) 101188417Sthompsa{ 102188417Sthompsa struct udp_port *p = (struct udp_port *)tp; 103188417Sthompsa struct sockaddr_in addr; 104188417Sthompsa u_int32_t ip; 105188417Sthompsa 106188417Sthompsa if ((p->input.fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 107188417Sthompsa syslog(LOG_ERR, "creating UDP socket: %m"); 108188417Sthompsa return (SNMP_ERR_RES_UNAVAIL); 109188417Sthompsa } 110188417Sthompsa ip = (p->addr[0] << 24) | (p->addr[1] << 16) | (p->addr[2] << 8) | 111188417Sthompsa p->addr[3]; 112188417Sthompsa memset(&addr, 0, sizeof(addr)); 113184610Salfred addr.sin_addr.s_addr = htonl(ip); 114184610Salfred addr.sin_port = htons(p->port); 115249584Sgabor addr.sin_family = AF_INET; 116184610Salfred addr.sin_len = sizeof(addr); 117188417Sthompsa if (bind(p->input.fd, (struct sockaddr *)&addr, sizeof(addr))) { 118188417Sthompsa if (errno == EADDRNOTAVAIL) { 119184610Salfred close(p->input.fd); 120184610Salfred p->input.fd = -1; 121184610Salfred return (SNMP_ERR_INCONS_NAME); 122184610Salfred } 123188417Sthompsa syslog(LOG_ERR, "bind: %s:%u %m", inet_ntoa(addr.sin_addr), 124188417Sthompsa p->port); 125188417Sthompsa close(p->input.fd); 126188417Sthompsa p->input.fd = -1; 127188417Sthompsa return (SNMP_ERR_GENERR); 128188417Sthompsa } 129188417Sthompsa if ((p->input.id = fd_select(p->input.fd, udp_input, 130188417Sthompsa p, NULL)) == NULL) { 131188417Sthompsa close(p->input.fd); 132188417Sthompsa p->input.fd = -1; 133188417Sthompsa return (SNMP_ERR_GENERR); 134188417Sthompsa } 135188417Sthompsa return (SNMP_ERR_NOERROR); 136188417Sthompsa} 137188417Sthompsa 138188417Sthompsa/* 139184610Salfred * Create a new SNMP Port object and start it, if we are not 140184610Salfred * in initialisation mode. The arguments are in host byte order. 141184610Salfred */ 142184610Salfredstatic int 143188417Sthompsaudp_open_port(u_int8_t *addr, u_int32_t udp_port, struct udp_port **pp) 144188417Sthompsa{ 145188417Sthompsa struct udp_port *port; 146188417Sthompsa int err; 147188417Sthompsa 148188417Sthompsa if (udp_port > 0xffff) 149184610Salfred return (SNMP_ERR_NO_CREATION); 150184610Salfred if ((port = malloc(sizeof(*port))) == NULL) 151188417Sthompsa return (SNMP_ERR_GENERR); 152188417Sthompsa memset(port, 0, sizeof(*port)); 153184610Salfred 154184610Salfred /* initialize common part */ 155184610Salfred port->tport.index.len = 5; 156184610Salfred port->tport.index.subs[0] = addr[0]; 157188417Sthompsa port->tport.index.subs[1] = addr[1]; 158188417Sthompsa port->tport.index.subs[2] = addr[2]; 159188417Sthompsa port->tport.index.subs[3] = addr[3]; 160188417Sthompsa port->tport.index.subs[4] = udp_port; 161188417Sthompsa 162188417Sthompsa port->addr[0] = addr[0]; 163188417Sthompsa port->addr[1] = addr[1]; 164188417Sthompsa port->addr[2] = addr[2]; 165188417Sthompsa port->addr[3] = addr[3]; 166188417Sthompsa port->port = udp_port; 167188417Sthompsa 168188417Sthompsa port->input.fd = -1; 169188417Sthompsa port->input.id = NULL; 170188417Sthompsa port->input.stream = 0; 171184610Salfred port->input.cred = 0; 172184610Salfred port->input.peer = (struct sockaddr *)&port->ret; 173184610Salfred port->input.peerlen = sizeof(port->ret); 174184610Salfred 175188417Sthompsa trans_insert_port(my_trans, &port->tport); 176188417Sthompsa 177188417Sthompsa if (community != COMM_INITIALIZE && 178188417Sthompsa (err = udp_init_port(&port->tport)) != SNMP_ERR_NOERROR) { 179188417Sthompsa udp_close_port(&port->tport); 180188417Sthompsa return (err); 181188417Sthompsa } 182188417Sthompsa *pp = port; 183188417Sthompsa return (SNMP_ERR_NOERROR); 184188417Sthompsa} 185188417Sthompsa 186188417Sthompsa/* 187188417Sthompsa * Close an SNMP port 188188417Sthompsa */ 189188417Sthompsastatic void 190188417Sthompsaudp_close_port(struct tport *tp) 191188417Sthompsa{ 192188417Sthompsa struct udp_port *port = (struct udp_port *)tp; 193188417Sthompsa 194188417Sthompsa snmpd_input_close(&port->input); 195188417Sthompsa trans_remove_port(tp); 196188417Sthompsa free(port); 197188417Sthompsa} 198188417Sthompsa 199188417Sthompsa/* 200188417Sthompsa * Send something 201188417Sthompsa */ 202188417Sthompsastatic ssize_t 203188417Sthompsaudp_send(struct tport *tp, const u_char *buf, size_t len, 204188417Sthompsa const struct sockaddr *addr, size_t addrlen) 205188417Sthompsa{ 206188417Sthompsa struct udp_port *p = (struct udp_port *)tp; 207188417Sthompsa 208188417Sthompsa return (sendto(p->input.fd, buf, len, 0, addr, addrlen)); 209188417Sthompsa} 210188417Sthompsa 211188417Sthompsa/* 212188417Sthompsa * Port table 213188417Sthompsa */ 214188417Sthompsaint 215188417Sthompsaop_snmp_port(struct snmp_context *ctx, struct snmp_value *value, 216188417Sthompsa u_int sub, u_int iidx, enum snmp_op op) 217188417Sthompsa{ 218188417Sthompsa asn_subid_t which = value->var.subs[sub-1]; 219188417Sthompsa struct udp_port *p; 220188417Sthompsa u_int8_t addr[4]; 221188417Sthompsa u_int32_t port; 222188417Sthompsa 223188417Sthompsa switch (op) { 224188417Sthompsa 225188417Sthompsa case SNMP_OP_GETNEXT: 226188417Sthompsa if ((p = (struct udp_port *)trans_next_port(my_trans, 227188417Sthompsa &value->var, sub)) == NULL) 228188417Sthompsa return (SNMP_ERR_NOSUCHNAME); 229188417Sthompsa index_append(&value->var, sub, &p->tport.index); 230188417Sthompsa break; 231188417Sthompsa 232188417Sthompsa case SNMP_OP_GET: 233188417Sthompsa if ((p = (struct udp_port *)trans_find_port(my_trans, 234188417Sthompsa &value->var, sub)) == NULL) 235188417Sthompsa return (SNMP_ERR_NOSUCHNAME); 236188417Sthompsa break; 237188417Sthompsa 238188417Sthompsa case SNMP_OP_SET: 239188417Sthompsa p = (struct udp_port *)trans_find_port(my_trans, 240188417Sthompsa &value->var, sub); 241188417Sthompsa ctx->scratch->int1 = (p != NULL); 242188417Sthompsa 243188417Sthompsa if (which != LEAF_begemotSnmpdPortStatus) 244188417Sthompsa abort(); 245188417Sthompsa if (!TRUTH_OK(value->v.integer)) 246188417Sthompsa return (SNMP_ERR_WRONG_VALUE); 247188417Sthompsa 248188417Sthompsa ctx->scratch->int2 = TRUTH_GET(value->v.integer); 249188417Sthompsa 250188417Sthompsa if (ctx->scratch->int2) { 251188417Sthompsa /* open an SNMP port */ 252188417Sthompsa if (p != NULL) 253188417Sthompsa /* already open - do nothing */ 254188417Sthompsa return (SNMP_ERR_NOERROR); 255188417Sthompsa 256188417Sthompsa if (index_decode(&value->var, sub, iidx, addr, &port)) 257188417Sthompsa return (SNMP_ERR_NO_CREATION); 258188417Sthompsa return (udp_open_port(addr, port, &p)); 259188417Sthompsa 260188417Sthompsa } else { 261188417Sthompsa /* close SNMP port - do in commit */ 262188417Sthompsa } 263188417Sthompsa return (SNMP_ERR_NOERROR); 264188417Sthompsa 265188417Sthompsa case SNMP_OP_ROLLBACK: 266188417Sthompsa p = (struct udp_port *)trans_find_port(my_trans, 267188417Sthompsa &value->var, sub); 268188417Sthompsa if (ctx->scratch->int1 == 0) { 269188417Sthompsa /* did not exist */ 270188417Sthompsa if (ctx->scratch->int2 == 1) { 271188417Sthompsa /* created */ 272188417Sthompsa if (p != NULL) 273188417Sthompsa udp_close_port(&p->tport); 274188417Sthompsa } 275188417Sthompsa } 276188417Sthompsa return (SNMP_ERR_NOERROR); 277188417Sthompsa 278188417Sthompsa case SNMP_OP_COMMIT: 279188417Sthompsa p = (struct udp_port *)trans_find_port(my_trans, 280188417Sthompsa &value->var, sub); 281188417Sthompsa if (ctx->scratch->int1 == 1) { 282188417Sthompsa /* did exist */ 283188417Sthompsa if (ctx->scratch->int2 == 0) { 284188417Sthompsa /* delete */ 285188417Sthompsa if (p != NULL) 286188417Sthompsa udp_close_port(&p->tport); 287188417Sthompsa } 288188417Sthompsa } 289188417Sthompsa return (SNMP_ERR_NOERROR); 290188417Sthompsa 291188417Sthompsa default: 292188417Sthompsa abort(); 293188417Sthompsa } 294188417Sthompsa 295188417Sthompsa /* 296188417Sthompsa * Come here to fetch the value 297188417Sthompsa */ 298188417Sthompsa switch (which) { 299188417Sthompsa 300188417Sthompsa case LEAF_begemotSnmpdPortStatus: 301188417Sthompsa value->v.integer = 1; 302188417Sthompsa break; 303188417Sthompsa 304188417Sthompsa default: 305188417Sthompsa abort(); 306188417Sthompsa } 307188417Sthompsa 308188417Sthompsa return (SNMP_ERR_NOERROR); 309188417Sthompsa} 310188417Sthompsa