trans_udp.c revision 310901
1124861Sharti/* 2124861Sharti * Copyright (c) 2003 3124861Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4124861Sharti * All rights reserved. 5124861Sharti * 6124861Sharti * Author: Harti Brandt <harti@freebsd.org> 7310901Sngie * 8133211Sharti * Redistribution and use in source and binary forms, with or without 9133211Sharti * modification, are permitted provided that the following conditions 10133211Sharti * are met: 11133211Sharti * 1. Redistributions of source code must retain the above copyright 12133211Sharti * notice, this list of conditions and the following disclaimer. 13124861Sharti * 2. Redistributions in binary form must reproduce the above copyright 14124861Sharti * notice, this list of conditions and the following disclaimer in the 15124861Sharti * documentation and/or other materials provided with the distribution. 16310901Sngie * 17133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133211Sharti * SUCH DAMAGE. 28124861Sharti * 29150920Sharti * $Begemot: bsnmp/snmpd/trans_udp.c,v 1.5 2005/10/04 08:46:56 brandt_h Exp $ 30124861Sharti * 31124861Sharti * UDP transport 32124861Sharti */ 33124861Sharti#include <sys/types.h> 34216294Ssyrinx#include <sys/queue.h> 35124861Sharti 36124861Sharti#include <stdlib.h> 37124861Sharti#include <syslog.h> 38124861Sharti#include <string.h> 39124861Sharti#include <errno.h> 40124861Sharti#include <unistd.h> 41124861Sharti 42124861Sharti#include <netinet/in.h> 43124861Sharti#include <arpa/inet.h> 44124861Sharti 45124861Sharti#include "snmpmod.h" 46124861Sharti#include "snmpd.h" 47124861Sharti#include "trans_udp.h" 48124861Sharti#include "tree.h" 49124861Sharti#include "oid.h" 50124861Sharti 51124861Shartistatic int udp_start(void); 52124861Shartistatic int udp_stop(int); 53124861Shartistatic void udp_close_port(struct tport *); 54124861Shartistatic int udp_init_port(struct tport *); 55124861Shartistatic ssize_t udp_send(struct tport *, const u_char *, size_t, 56124861Sharti const struct sockaddr *, size_t); 57124861Sharti 58124861Sharti/* exported */ 59124861Sharticonst struct transport_def udp_trans = { 60124861Sharti "udp", 61124861Sharti OIDX_begemotSnmpdTransUdp, 62124861Sharti udp_start, 63124861Sharti udp_stop, 64124861Sharti udp_close_port, 65124861Sharti udp_init_port, 66124861Sharti udp_send 67124861Sharti}; 68124861Shartistatic struct transport *my_trans; 69124861Sharti 70124861Shartistatic int 71124861Shartiudp_start(void) 72124861Sharti{ 73124861Sharti return (trans_register(&udp_trans, &my_trans)); 74124861Sharti} 75124861Sharti 76124861Shartistatic int 77124861Shartiudp_stop(int force __unused) 78124861Sharti{ 79124861Sharti if (my_trans != NULL) 80124861Sharti if (trans_unregister(my_trans) != 0) 81124861Sharti return (SNMP_ERR_GENERR); 82124861Sharti return (SNMP_ERR_NOERROR); 83124861Sharti} 84124861Sharti 85124861Sharti/* 86124861Sharti * A UDP port is ready 87124861Sharti */ 88124861Shartistatic void 89124861Shartiudp_input(int fd __unused, void *udata) 90124861Sharti{ 91124861Sharti struct udp_port *p = udata; 92124861Sharti 93124861Sharti p->input.peerlen = sizeof(p->ret); 94124861Sharti snmpd_input(&p->input, &p->tport); 95124861Sharti} 96124861Sharti 97124861Sharti/* 98124861Sharti * Create a UDP socket and bind it to the given port 99124861Sharti */ 100124861Shartistatic int 101124861Shartiudp_init_port(struct tport *tp) 102124861Sharti{ 103124861Sharti struct udp_port *p = (struct udp_port *)tp; 104124861Sharti struct sockaddr_in addr; 105124861Sharti u_int32_t ip; 106240271Sglebius const int on = 1; 107124861Sharti 108124861Sharti if ((p->input.fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 109124861Sharti syslog(LOG_ERR, "creating UDP socket: %m"); 110124861Sharti return (SNMP_ERR_RES_UNAVAIL); 111124861Sharti } 112124861Sharti ip = (p->addr[0] << 24) | (p->addr[1] << 16) | (p->addr[2] << 8) | 113124861Sharti p->addr[3]; 114124861Sharti memset(&addr, 0, sizeof(addr)); 115124861Sharti addr.sin_addr.s_addr = htonl(ip); 116124861Sharti addr.sin_port = htons(p->port); 117124861Sharti addr.sin_family = AF_INET; 118124861Sharti addr.sin_len = sizeof(addr); 119240734Sglebius if (addr.sin_addr.s_addr == INADDR_ANY && 120240734Sglebius setsockopt(p->input.fd, IPPROTO_IP, IP_RECVDSTADDR, &on, 121240734Sglebius sizeof(on)) == -1) { 122240734Sglebius syslog(LOG_ERR, "setsockopt(IP_RECVDSTADDR): %m"); 123240734Sglebius close(p->input.fd); 124240734Sglebius p->input.fd = -1; 125240734Sglebius return (SNMP_ERR_GENERR); 126240734Sglebius } 127124861Sharti if (bind(p->input.fd, (struct sockaddr *)&addr, sizeof(addr))) { 128124861Sharti if (errno == EADDRNOTAVAIL) { 129124861Sharti close(p->input.fd); 130124861Sharti p->input.fd = -1; 131124861Sharti return (SNMP_ERR_INCONS_NAME); 132124861Sharti } 133124861Sharti syslog(LOG_ERR, "bind: %s:%u %m", inet_ntoa(addr.sin_addr), 134124861Sharti p->port); 135124861Sharti close(p->input.fd); 136124861Sharti p->input.fd = -1; 137124861Sharti return (SNMP_ERR_GENERR); 138124861Sharti } 139124861Sharti if ((p->input.id = fd_select(p->input.fd, udp_input, 140124861Sharti p, NULL)) == NULL) { 141124861Sharti close(p->input.fd); 142124861Sharti p->input.fd = -1; 143124861Sharti return (SNMP_ERR_GENERR); 144124861Sharti } 145124861Sharti return (SNMP_ERR_NOERROR); 146124861Sharti} 147124861Sharti 148124861Sharti/* 149124861Sharti * Create a new SNMP Port object and start it, if we are not 150150920Sharti * in initialization mode. The arguments are in host byte order. 151124861Sharti */ 152124861Shartistatic int 153124861Shartiudp_open_port(u_int8_t *addr, u_int32_t udp_port, struct udp_port **pp) 154124861Sharti{ 155124861Sharti struct udp_port *port; 156124861Sharti int err; 157124861Sharti 158124861Sharti if (udp_port > 0xffff) 159124861Sharti return (SNMP_ERR_NO_CREATION); 160124861Sharti if ((port = malloc(sizeof(*port))) == NULL) 161124861Sharti return (SNMP_ERR_GENERR); 162124861Sharti memset(port, 0, sizeof(*port)); 163124861Sharti 164124861Sharti /* initialize common part */ 165124861Sharti port->tport.index.len = 5; 166124861Sharti port->tport.index.subs[0] = addr[0]; 167124861Sharti port->tport.index.subs[1] = addr[1]; 168124861Sharti port->tport.index.subs[2] = addr[2]; 169124861Sharti port->tport.index.subs[3] = addr[3]; 170124861Sharti port->tport.index.subs[4] = udp_port; 171124861Sharti 172124861Sharti port->addr[0] = addr[0]; 173124861Sharti port->addr[1] = addr[1]; 174124861Sharti port->addr[2] = addr[2]; 175124861Sharti port->addr[3] = addr[3]; 176124861Sharti port->port = udp_port; 177124861Sharti 178124861Sharti port->input.fd = -1; 179124861Sharti port->input.id = NULL; 180124861Sharti port->input.stream = 0; 181124861Sharti port->input.cred = 0; 182124861Sharti port->input.peer = (struct sockaddr *)&port->ret; 183124861Sharti port->input.peerlen = sizeof(port->ret); 184124861Sharti 185124861Sharti trans_insert_port(my_trans, &port->tport); 186124861Sharti 187124861Sharti if (community != COMM_INITIALIZE && 188124861Sharti (err = udp_init_port(&port->tport)) != SNMP_ERR_NOERROR) { 189124861Sharti udp_close_port(&port->tport); 190124861Sharti return (err); 191124861Sharti } 192124861Sharti *pp = port; 193124861Sharti return (SNMP_ERR_NOERROR); 194124861Sharti} 195124861Sharti 196124861Sharti/* 197124861Sharti * Close an SNMP port 198124861Sharti */ 199124861Shartistatic void 200124861Shartiudp_close_port(struct tport *tp) 201124861Sharti{ 202124861Sharti struct udp_port *port = (struct udp_port *)tp; 203124861Sharti 204124861Sharti snmpd_input_close(&port->input); 205124861Sharti trans_remove_port(tp); 206124861Sharti free(port); 207124861Sharti} 208124861Sharti 209124861Sharti/* 210124861Sharti * Send something 211124861Sharti */ 212124861Shartistatic ssize_t 213124861Shartiudp_send(struct tport *tp, const u_char *buf, size_t len, 214124861Sharti const struct sockaddr *addr, size_t addrlen) 215124861Sharti{ 216124861Sharti struct udp_port *p = (struct udp_port *)tp; 217124861Sharti 218124861Sharti return (sendto(p->input.fd, buf, len, 0, addr, addrlen)); 219124861Sharti} 220124861Sharti 221124861Sharti/* 222124861Sharti * Port table 223124861Sharti */ 224124861Shartiint 225124861Shartiop_snmp_port(struct snmp_context *ctx, struct snmp_value *value, 226124861Sharti u_int sub, u_int iidx, enum snmp_op op) 227124861Sharti{ 228124861Sharti asn_subid_t which = value->var.subs[sub-1]; 229124861Sharti struct udp_port *p; 230124861Sharti u_int8_t addr[4]; 231124861Sharti u_int32_t port; 232124861Sharti 233124861Sharti switch (op) { 234124861Sharti 235124861Sharti case SNMP_OP_GETNEXT: 236124861Sharti if ((p = (struct udp_port *)trans_next_port(my_trans, 237124861Sharti &value->var, sub)) == NULL) 238124861Sharti return (SNMP_ERR_NOSUCHNAME); 239124861Sharti index_append(&value->var, sub, &p->tport.index); 240124861Sharti break; 241124861Sharti 242124861Sharti case SNMP_OP_GET: 243124861Sharti if ((p = (struct udp_port *)trans_find_port(my_trans, 244124861Sharti &value->var, sub)) == NULL) 245124861Sharti return (SNMP_ERR_NOSUCHNAME); 246124861Sharti break; 247124861Sharti 248124861Sharti case SNMP_OP_SET: 249124861Sharti p = (struct udp_port *)trans_find_port(my_trans, 250124861Sharti &value->var, sub); 251124861Sharti ctx->scratch->int1 = (p != NULL); 252124861Sharti 253124861Sharti if (which != LEAF_begemotSnmpdPortStatus) 254124861Sharti abort(); 255124861Sharti if (!TRUTH_OK(value->v.integer)) 256124861Sharti return (SNMP_ERR_WRONG_VALUE); 257124861Sharti 258124861Sharti ctx->scratch->int2 = TRUTH_GET(value->v.integer); 259124861Sharti 260124861Sharti if (ctx->scratch->int2) { 261124861Sharti /* open an SNMP port */ 262124861Sharti if (p != NULL) 263124861Sharti /* already open - do nothing */ 264124861Sharti return (SNMP_ERR_NOERROR); 265124861Sharti 266124861Sharti if (index_decode(&value->var, sub, iidx, addr, &port)) 267124861Sharti return (SNMP_ERR_NO_CREATION); 268124861Sharti return (udp_open_port(addr, port, &p)); 269124861Sharti 270124861Sharti } else { 271124861Sharti /* close SNMP port - do in commit */ 272124861Sharti } 273124861Sharti return (SNMP_ERR_NOERROR); 274124861Sharti 275124861Sharti case SNMP_OP_ROLLBACK: 276124861Sharti p = (struct udp_port *)trans_find_port(my_trans, 277124861Sharti &value->var, sub); 278124861Sharti if (ctx->scratch->int1 == 0) { 279124861Sharti /* did not exist */ 280124861Sharti if (ctx->scratch->int2 == 1) { 281124861Sharti /* created */ 282124861Sharti if (p != NULL) 283124861Sharti udp_close_port(&p->tport); 284124861Sharti } 285124861Sharti } 286124861Sharti return (SNMP_ERR_NOERROR); 287124861Sharti 288124861Sharti case SNMP_OP_COMMIT: 289124861Sharti p = (struct udp_port *)trans_find_port(my_trans, 290124861Sharti &value->var, sub); 291124861Sharti if (ctx->scratch->int1 == 1) { 292124861Sharti /* did exist */ 293124861Sharti if (ctx->scratch->int2 == 0) { 294124861Sharti /* delete */ 295124861Sharti if (p != NULL) 296124861Sharti udp_close_port(&p->tport); 297124861Sharti } 298124861Sharti } 299124861Sharti return (SNMP_ERR_NOERROR); 300124861Sharti 301124861Sharti default: 302124861Sharti abort(); 303124861Sharti } 304124861Sharti 305124861Sharti /* 306124861Sharti * Come here to fetch the value 307124861Sharti */ 308124861Sharti switch (which) { 309124861Sharti 310124861Sharti case LEAF_begemotSnmpdPortStatus: 311124861Sharti value->v.integer = 1; 312124861Sharti break; 313124861Sharti 314124861Sharti default: 315124861Sharti abort(); 316124861Sharti } 317124861Sharti 318124861Sharti return (SNMP_ERR_NOERROR); 319124861Sharti} 320