www.usr.com/support/gpl/USR9113_release1.0.tar.gz
[bcm963xx.git] / userapps / opensource / net-snmp / snmplib / snmpUDPDomain.c
1 #include <net-snmp/net-snmp-config.h>
2
3 #include <stdio.h>
4 #include <sys/types.h>
5 #include <ctype.h>
6 #include <errno.h>
7
8 #if HAVE_STRING_H
9 #include <string.h>
10 #else
11 #include <strings.h>
12 #endif
13 #if HAVE_STDLIB_H
14 #include <stdlib.h>
15 #endif
16 #if HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19 #if HAVE_SYS_SOCKET_H
20 #include <sys/socket.h>
21 #endif
22 #if HAVE_NETINET_IN_H
23 #include <netinet/in.h>
24 #endif
25 #if HAVE_ARPA_INET_H
26 #include <arpa/inet.h>
27 #endif
28 #if HAVE_NETDB_H
29 #include <netdb.h>
30 #endif
31
32 #if HAVE_DMALLOC_H
33 #include <dmalloc.h>
34 #endif
35
36 #include <net-snmp/types.h>
37 #include <net-snmp/output_api.h>
38 #include <net-snmp/config_api.h>
39
40 #include <net-snmp/library/snmp_transport.h>
41 #include <net-snmp/library/snmpUDPDomain.h>
42
43 #ifndef INADDR_NONE
44 #define INADDR_NONE     -1
45 #endif
46
47 static netsnmp_tdomain udpDomain;
48
49 /*
50  * Return a string representing the address in data, or else the "far end"
51  * address if data is NULL.  
52  */
53
54 static char *
55 netsnmp_udp_fmtaddr(netsnmp_transport *t, void *data, int len)
56 {
57     struct sockaddr_in *to = NULL;
58
59     if (data != NULL && len == sizeof(struct sockaddr_in)) {
60         to = (struct sockaddr_in *) data;
61     } else if (t != NULL && t->data != NULL) {
62         to = (struct sockaddr_in *) t->data;
63     }
64     if (to == NULL) {
65         return strdup("UDP: unknown");
66     } else {
67         char tmp[64];
68
69         /*
70          * Here we just print the IP address of the peer for compatibility
71          * purposes.  It would be nice if we could include the port number and
72          * some indication of the domain (c.f. AAL5PVC).  
73          */
74
75         sprintf(tmp, "%s", inet_ntoa(to->sin_addr));
76         return strdup(tmp);
77     }
78 }
79
80
81
82 /*
83  * You can write something into opaque that will subsequently get passed back 
84  * to your send function if you like.  For instance, you might want to
85  * remember where a PDU came from, so that you can send a reply there...  
86  */
87
88 static int
89 netsnmp_udp_recv(netsnmp_transport *t, void *buf, int size,
90                  void **opaque, int *olength)
91 {
92     int             rc = -1;
93     socklen_t       fromlen = sizeof(struct sockaddr);
94     struct sockaddr *from;
95
96     if (t != NULL && t->sock >= 0) {
97         from = (struct sockaddr *) malloc(sizeof(struct sockaddr_in));
98         if (from == NULL) {
99             *opaque = NULL;
100             *olength = 0;
101             return -1;
102         } else {
103             memset(from, 0, fromlen);
104         }
105
106         while (rc < 0) {
107             rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
108             if (rc < 0 && errno != EINTR) {
109                 break;
110             }
111         }
112
113         if (rc >= 0) {
114             char *string = netsnmp_udp_fmtaddr(NULL, from, fromlen);
115             DEBUGMSGTL(("netsnmp_udp",
116                         "recvfrom fd %d got %d bytes (from %s)\n",
117                         t->sock, rc, string));
118             free(string);
119         } else {
120             DEBUGMSGTL(("netsnmp_udp", "recvfrom fd %d err %d (\"%s\")\n",
121                         t->sock, errno, strerror(errno)));
122         }
123         *opaque = (void *)from;
124         *olength = sizeof(struct sockaddr_in);
125     }
126     return rc;
127 }
128
129
130
131 static int
132 netsnmp_udp_send(netsnmp_transport *t, void *buf, int size,
133                  void **opaque, int *olength)
134 {
135     int rc = -1;
136     struct sockaddr *to = NULL;
137
138     if (opaque != NULL && *opaque != NULL &&
139         *olength == sizeof(struct sockaddr_in)) {
140         to = (struct sockaddr *) (*opaque);
141     } else if (t != NULL && t->data != NULL &&
142                t->data_length == sizeof(struct sockaddr_in)) {
143         to = (struct sockaddr *) (t->data);
144     }
145
146     if (to != NULL && t != NULL && t->sock >= 0) {
147         char *string = netsnmp_udp_fmtaddr(NULL, (void *) to,
148                                         sizeof(struct sockaddr_in));
149         DEBUGMSGTL(("netsnmp_udp", "send %d bytes from %p to %s on fd %d\n",
150                     size, buf, string, t->sock));
151         free(string);
152         while (rc < 0) {
153             rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr));
154             if (rc < 0 && errno != EINTR) {
155                 break;
156             }
157         }
158     }
159     return rc;
160 }
161
162
163
164 static int
165 netsnmp_udp_close(netsnmp_transport *t)
166 {
167     int rc = -1;
168     if (t->sock >= 0) {
169 #ifndef HAVE_CLOSESOCKET
170         rc = close(t->sock);
171 #else
172         rc = closesocket(t->sock);
173 #endif
174         t->sock = -1;
175     }
176     return rc;
177 }
178
179
180
181 /*
182  * Open a UDP-based transport for SNMP.  Local is TRUE if addr is the local
183  * address to bind to (i.e. this is a server-type session); otherwise addr is 
184  * the remote address to send things to.  
185  */
186
187 netsnmp_transport *
188 netsnmp_udp_transport(struct sockaddr_in *addr, int local)
189 {
190     netsnmp_transport *t = NULL;
191     int             rc = 0, udpbuf = (1 << 17);
192     char           *string = NULL;
193
194     if (addr == NULL || addr->sin_family != AF_INET) {
195         return NULL;
196     }
197
198     t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
199     if (t == NULL) {
200         return NULL;
201     }
202
203     string = netsnmp_udp_fmtaddr(NULL, (void *)addr, 
204                                  sizeof(struct sockaddr_in));
205     DEBUGMSGTL(("netsnmp_udp", "open %s %s\n", local ? "local" : "remote",
206                 string));
207     free(string);
208
209     memset(t, 0, sizeof(netsnmp_transport));
210
211     t->domain = netsnmpUDPDomain;
212     t->domain_length = netsnmpUDPDomain_len;
213
214     t->sock = socket(PF_INET, SOCK_DGRAM, 0);
215     if (t->sock < 0) {
216         netsnmp_transport_free(t);
217         return NULL;
218     }
219 #ifdef  SO_BSDCOMPAT
220     /*
221      * Patch for Linux.  Without this, UDP packets that fail get an ICMP
222      * response.  Linux turns the failed ICMP response into an error message
223      * and return value, unlike all other OS's.  
224      */
225     if (0 == netsnmp_os_prematch("Linux","2.4"))
226     {
227         int             one = 1;
228         setsockopt(t->sock, SOL_SOCKET, SO_BSDCOMPAT, (void *) &one,
229                    sizeof(one));
230     }
231 #endif                          /*SO_BSDCOMPAT */
232     /*
233      * SO_REUSEADDR will allow multiple apps to open the same port at
234      * the same time. Only the last one to open the socket will get
235      * data. Obviously, for an agent, this is a bad thing. There should
236      * only be one listener.
237      */
238 #ifdef ALLOW_PORT_HIJACKING
239 #ifdef  SO_REUSEADDR
240     /*
241      * Allow the same port to be specified multiple times without failing.
242      *    (useful for a listener)
243      */
244     {
245         int             one = 1;
246         setsockopt(t->sock, SOL_SOCKET, SO_REUSEADDR, (void *) &one,
247                    sizeof(one));
248     }
249 #endif                          /*SO_REUSEADDR */
250 #endif
251     /*
252      * Try to set the send and receive buffers to a reasonably large value, so
253      * that we can send and receive big PDUs (defaults to 8192 bytes (!) on
254      * Solaris, for instance).  Don't worry too much about errors -- just
255      * plough on regardless.  
256      */
257
258 #ifdef  SO_SNDBUF
259     if (setsockopt
260         (t->sock, SOL_SOCKET, SO_SNDBUF, (void *) &udpbuf,
261          sizeof(int)) != 0) {
262         DEBUGMSGTL(("netsnmp_udp", "couldn't set SO_SNDBUF to %d bytes: %s\n",
263                     udpbuf, strerror(errno)));
264     }
265 #endif                          /*SO_SNDBUF */
266
267 #ifdef  SO_RCVBUF
268     if (setsockopt
269         (t->sock, SOL_SOCKET, SO_RCVBUF, (void *) &udpbuf,
270          sizeof(int)) != 0) {
271         DEBUGMSGTL(("netsnmp_udp", "couldn't set SO_RCVBUF to %d bytes: %s\n",
272                     udpbuf, strerror(errno)));
273     }
274 #endif                          /*SO_RCVBUF */
275
276     if (local) {
277         /*
278          * This session is inteneded as a server, so we must bind on to the
279          * given IP address, which may include an interface address, or could
280          * be INADDR_ANY, but certainly includes a port number.
281          */
282
283         t->local = malloc(6);
284         if (t->local == NULL) {
285             netsnmp_transport_free(t);
286             return NULL;
287         }
288         memcpy(t->local, (u_char *) & (addr->sin_addr.s_addr), 4);
289         t->local[4] = (htons(addr->sin_port) & 0xff00) >> 8;
290         t->local[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
291         t->local_length = 6;
292
293         rc = bind(t->sock, (struct sockaddr *) addr,
294                   sizeof(struct sockaddr));
295         if (rc != 0) {
296             netsnmp_udp_close(t);
297             netsnmp_transport_free(t);
298             return NULL;
299         }
300         t->data = NULL;
301         t->data_length = 0;
302     } else {
303         /*
304          * This is a client session.  Save the address in the
305          * transport-specific data pointer for later use by netsnmp_udp_send.
306          */
307
308         t->data = malloc(sizeof(struct sockaddr_in));
309         t->remote = malloc(6);
310         if (t->data == NULL || t->remote == NULL) {
311             netsnmp_transport_free(t);
312             return NULL;
313         }
314         memcpy(t->remote, (u_char *) & (addr->sin_addr.s_addr), 4);
315         t->remote[4] = (htons(addr->sin_port) & 0xff00) >> 8;
316         t->remote[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
317         t->remote_length = 6;
318         memcpy(t->data, addr, sizeof(struct sockaddr_in));
319         t->data_length = sizeof(struct sockaddr_in);
320     }
321
322     /*
323      * 16-bit length field, 8 byte UDP header, 20 byte IPv4 header  
324      */
325
326     t->msgMaxSize = 0xffff - 8 - 20;
327     t->f_recv     = netsnmp_udp_recv;
328     t->f_send     = netsnmp_udp_send;
329     t->f_close    = netsnmp_udp_close;
330     t->f_accept   = NULL;
331     t->f_fmtaddr  = netsnmp_udp_fmtaddr;
332
333     return t;
334 }
335
336
337
338 int
339 netsnmp_sockaddr_in(struct sockaddr_in *addr,
340                     const char *inpeername, int remote_port)
341 {
342     char           *cp = NULL, *peername = NULL;
343
344     if (addr == NULL) {
345         return 0;
346     }
347     memset(addr, 0, sizeof(struct sockaddr_in));
348
349     DEBUGMSGTL(("netsnmp_sockaddr_in", "addr %p, peername \"%s\"\n",
350                 addr, inpeername ? inpeername : "[NIL]"));
351
352     addr->sin_addr.s_addr = htonl(INADDR_ANY);
353     addr->sin_family = AF_INET;
354     if (remote_port > 0) {
355         addr->sin_port = htons(remote_port);
356     } else if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
357                                   NETSNMP_DS_LIB_DEFAULT_PORT) > 0) {
358         addr->sin_port = htons(netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
359                                                  NETSNMP_DS_LIB_DEFAULT_PORT));
360     } else {
361         addr->sin_port = htons(SNMP_PORT);
362     }
363
364     if (inpeername != NULL) {
365         /*
366          * Duplicate the peername because we might want to mank around with
367          * it.  
368          */
369
370         peername = strdup(inpeername);
371         if (peername == NULL) {
372             return 0;
373         }
374
375         /*
376          * Try and extract an appended port number.  
377          */
378         cp = strchr(peername, ':');
379         if (cp != NULL) {
380             *cp = '\0';
381             cp++;
382             if (atoi(cp) != 0) {
383                 DEBUGMSGTL(("netsnmp_sockaddr_in",
384                             "port number suffix :%d\n", atoi(cp)));
385                 addr->sin_port = htons(atoi(cp));
386             }
387         }
388
389         for (cp = peername; *cp && isdigit((int) *cp); cp++);
390         if (!*cp && atoi(peername) != 0) {
391             /*
392              * Okay, it looks like just a port number.  
393              */
394             DEBUGMSGTL(("netsnmp_sockaddr_in", "totally numeric: %d\n",
395                         atoi(peername)));
396             addr->sin_port = htons(atoi(peername));
397         } else if (inet_addr(peername) != INADDR_NONE) {
398             /*
399              * It looks like an IP address.  
400              */
401             DEBUGMSGTL(("netsnmp_sockaddr_in", "IP address\n"));
402             addr->sin_addr.s_addr = inet_addr(peername);
403         } else {
404             /*
405              * Well, it must be a hostname then.  
406              */
407 #ifdef  HAVE_GETHOSTBYNAME
408             struct hostent *hp = gethostbyname(peername);
409             if (hp == NULL) {
410                 DEBUGMSGTL(("netsnmp_sockaddr_in",
411                             "hostname (couldn't resolve)\n"));
412                 free(peername);
413                 return 0;
414             } else {
415                 if (hp->h_addrtype != AF_INET) {
416                     DEBUGMSGTL(("netsnmp_sockaddr_in",
417                                 "hostname (not AF_INET!)\n"));
418                     free(peername);
419                     return 0;
420                 } else {
421                     DEBUGMSGTL(("netsnmp_sockaddr_in",
422                                 "hostname (resolved okay)\n"));
423                     memcpy(&(addr->sin_addr), hp->h_addr, hp->h_length);
424                 }
425             }
426 #else                           /*HAVE_GETHOSTBYNAME */
427             DEBUGMSGTL(("netsnmp_sockaddr_in",
428                         "hostname (no gethostbyname)\n"));
429             free(peername);
430             return 0;
431 #endif                          /*HAVE_GETHOSTBYNAME */
432         }
433     } else {
434         DEBUGMSGTL(("netsnmp_sockaddr_in", "NULL peername"));
435         return 0;
436     }
437     DEBUGMSGTL(("netsnmp_sockaddr_in", "return { AF_INET, %s:%hu }\n",
438                 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port)));
439     free(peername);
440     return 1;
441 }
442
443 /*
444  * The following functions provide the "com2sec" configuration token
445  * functionality for compatibility.  
446  */
447
448 #define EXAMPLE_NETWORK         "NETWORK"
449 #define EXAMPLE_COMMUNITY       "COMMUNITY"
450
451 typedef struct _com2SecEntry {
452     char            community[VACMSTRINGLEN];
453     unsigned long   network;
454     unsigned long   mask;
455     char            secName[VACMSTRINGLEN];
456     struct _com2SecEntry *next;
457 } com2SecEntry;
458
459 com2SecEntry   *com2SecList = NULL, *com2SecListLast = NULL;
460
461 void
462 netsnmp_udp_parse_security(const char *token, char *param)
463 {
464     char           *secName = NULL, *community = NULL, *source = NULL;
465     char           *cp = NULL;
466     const char     *strmask = NULL;
467     com2SecEntry   *e = NULL;
468     unsigned long   network = 0, mask = 0;
469
470     /*
471      * Get security, source address/netmask and community strings.  
472      */
473
474     secName = strtok(param, "\t\n ");
475     if (secName == NULL) {
476         config_perror("missing NAME parameter");
477         return;
478     } else if (strlen(secName) > (VACMSTRINGLEN - 1)) {
479         config_perror("security name too long");
480         return;
481     }
482     source = strtok(NULL, "\t\n ");
483     if (source == NULL) {
484         config_perror("missing SOURCE parameter");
485         return;
486     } else if (strncmp(source, EXAMPLE_NETWORK, strlen(EXAMPLE_NETWORK)) ==
487                0) {
488         config_perror("example config NETWORK not properly configured");
489         return;
490     }
491     community = strtok(NULL, "\t\n ");
492     if (community == NULL) {
493         config_perror("missing COMMUNITY parameter\n");
494         return;
495     } else
496         if (strncmp
497             (community, EXAMPLE_COMMUNITY, strlen(EXAMPLE_COMMUNITY))
498             == 0) {
499         config_perror("example config COMMUNITY not properly configured");
500         return;
501     } else if (strlen(community) > (VACMSTRINGLEN - 1)) {
502         config_perror("community name too long");
503         return;
504     }
505
506     /*
507      * Process the source address/netmask string.  
508      */
509
510     cp = strchr(source, '/');
511     if (cp != NULL) {
512         /*
513          * Mask given.  
514          */
515         *cp = '\0';
516         strmask = cp + 1;
517     }
518
519     /*
520      * Deal with the network part first.  
521      */
522
523     if ((strcmp(source, "default") == 0)
524         || (strcmp(source, "0.0.0.0") == 0)) {
525         network = 0;
526         strmask = "0.0.0.0";
527     } else {
528         /*
529          * Try interpreting as a dotted quad.  
530          */
531         network = inet_addr(source);
532
533         if (network == (unsigned long) -1) {
534             /*
535              * Nope, wasn't a dotted quad.  Must be a hostname.  
536              */
537 #ifdef  HAVE_GETHOSTBYNAME
538             struct hostent *hp = gethostbyname(source);
539             if (hp == NULL) {
540                 config_perror("bad source address");
541                 return;
542             } else {
543                 if (hp->h_addrtype != AF_INET) {
544                     config_perror("no IP address for source hostname");
545                     return;
546                 }
547                 network = *((unsigned long *) hp->h_addr);
548             }
549 #else                           /*HAVE_GETHOSTBYNAME */
550             /*
551              * Oh dear.  
552              */
553             config_perror("cannot resolve source hostname");
554             return;
555 #endif                          /*HAVE_GETHOSTBYNAME */
556         }
557     }
558
559     /*
560      * Now work out the mask.  
561      */
562
563     if (strmask == NULL || *strmask == '\0') {
564         /*
565          * No mask was given.  Use 255.255.255.255.  
566          */
567         mask = 0xffffffffL;
568     } else {
569         if (strchr(strmask, '.')) {
570             /*
571              * Try to interpret mask as a dotted quad.  
572              */
573             mask = inet_addr(strmask);
574             if (mask == (unsigned long) -1 &&
575                 strncmp(strmask, "255.255.255.255", 15) != 0) {
576                 config_perror("bad mask");
577                 return;
578             }
579         } else {
580             /*
581              * Try to interpret mask as a "number of 1 bits".  
582              */
583             int             maskLen = atoi(strmask), maskBit = 0x80000000L;
584             if (maskLen <= 0 || maskLen > 32) {
585                 config_perror("bad mask length");
586                 return;
587             }
588             while (maskLen--) {
589                 mask |= maskBit;
590                 maskBit >>= 1;
591             }
592             mask = htonl(mask);
593         }
594     }
595
596     /*
597      * Check that the network and mask are consistent.  
598      */
599
600     if (network & ~mask) {
601         config_perror("source/mask mismatch");
602         return;
603     }
604
605     e = (com2SecEntry *) malloc(sizeof(com2SecEntry));
606     if (e == NULL) {
607         config_perror("memory error");
608         return;
609     }
610
611     /*
612      * Everything is okay.  Copy the parameters to the structure allocated
613      * above and add it to END of the list.  
614      */
615
616     DEBUGMSGTL(("netsnmp_udp_parse_security",
617                 "<\"%s\", 0x%08x/0x%08x> => \"%s\"\n", community, network,
618                 mask, secName));
619
620     strcpy(e->secName, secName);
621     strcpy(e->community, community);
622     e->network = network;
623     e->mask = mask;
624     e->next = NULL;
625
626     if (com2SecListLast != NULL) {
627         com2SecListLast->next = e;
628         com2SecListLast = e;
629     } else {
630         com2SecListLast = com2SecList = e;
631     }
632 }
633
634
635 void
636 netsnmp_udp_com2SecList_free(void)
637 {
638     com2SecEntry   *e = com2SecList;
639     while (e != NULL) {
640         com2SecEntry   *tmp = e;
641         e = e->next;
642         free(tmp);
643     }
644     com2SecList = com2SecListLast = NULL;
645 }
646
647
648 void
649 netsnmp_udp_agent_config_tokens_register(void)
650 {
651     register_app_config_handler("com2sec", netsnmp_udp_parse_security,
652                                 netsnmp_udp_com2SecList_free,
653                                 "name IPv4-network-address[/netmask] community");
654 }
655
656
657
658 /*
659  * Return 0 if there are no com2sec entries, or return 1 if there ARE com2sec 
660  * entries.  On return, if a com2sec entry matched the passed parameters,
661  * then *secName points at the appropriate security name, or is NULL if the
662  * parameters did not match any com2sec entry.  
663  */
664
665 int
666 netsnmp_udp_getSecName(void *opaque, int olength,
667                        const char *community,
668                        size_t community_len, char **secName)
669 {
670     com2SecEntry   *c;
671     struct sockaddr_in *from = (struct sockaddr_in *) opaque;
672     char           *ztcommunity = NULL;
673
674     /*
675      * Special case if there are NO entries (as opposed to no MATCHING
676      * entries).  
677      */
678
679     if (com2SecList == NULL) {
680         DEBUGMSGTL(("netsnmp_udp_getSecName", "no com2sec entries\n"));
681         if (secName != NULL) {
682             *secName = NULL;
683         }
684         return 0;
685     }
686
687     /*
688      * If there is no IPv4 source address, then there can be no valid security
689      * name.  
690      */
691
692     if (opaque == NULL || olength != sizeof(struct sockaddr_in) ||
693         from->sin_family != AF_INET) {
694         DEBUGMSGTL(("netsnmp_udp_getSecName",
695                     "no IPv4 source address in PDU?\n"));
696         if (secName != NULL) {
697             *secName = NULL;
698         }
699         return 1;
700     }
701
702     DEBUGIF("netsnmp_udp_getSecName") {
703         ztcommunity = (char *)malloc(community_len + 1);
704         if (ztcommunity != NULL) {
705             memcpy(ztcommunity, community, community_len);
706             ztcommunity[community_len] = '\0';
707         }
708
709         DEBUGMSGTL(("netsnmp_udp_getSecName", "resolve <\"%s\", 0x%08x>\n",
710                     ztcommunity ? ztcommunity : "<malloc error>",
711                     from->sin_addr.s_addr));
712     }
713     for (c = com2SecList; c != NULL; c = c->next) {
714         DEBUGMSGTL(("netsnmp_udp_getSecName","compare <\"%s\", 0x%08x/0x%08x>",
715                     c->community, c->network, c->mask));
716         if ((community_len == strlen(c->community)) &&
717             (memcmp(community, c->community, community_len) == 0) &&
718             ((from->sin_addr.s_addr & c->mask) == c->network)) {
719             DEBUGMSG(("netsnmp_udp_getSecName", "... SUCCESS\n"));
720             if (secName != NULL) {
721                 *secName = c->secName;
722             }
723             break;
724         }
725         DEBUGMSG(("netsnmp_udp_getSecName", "... nope\n"));
726     }
727     if (ztcommunity != NULL) {
728         free(ztcommunity);
729     }
730     return 1;
731 }
732
733
734 netsnmp_transport *
735 netsnmp_udp_create_tstring(const char *string, int local)
736 {
737     struct sockaddr_in addr;
738
739     if (netsnmp_sockaddr_in(&addr, string, 0)) {
740         return netsnmp_udp_transport(&addr, local);
741     } else {
742         return NULL;
743     }
744 }
745
746
747 netsnmp_transport *
748 netsnmp_udp_create_ostring(const u_char * o, size_t o_len, int local)
749 {
750     struct sockaddr_in addr;
751
752     if (o_len == 6) {
753         addr.sin_family = AF_INET;
754         memcpy((u_char *) & (addr.sin_addr.s_addr), o, 4);
755         addr.sin_port = ntohs((o[4] << 8) + o[5]);
756         return netsnmp_udp_transport(&addr, local);
757     }
758     return NULL;
759 }
760
761
762 void
763 netsnmp_udp_ctor(void)
764 {
765     udpDomain.name = netsnmpUDPDomain;
766     udpDomain.name_length = netsnmpUDPDomain_len;
767     udpDomain.prefix = calloc(2, sizeof(char *));
768     udpDomain.prefix[0] = "udp";
769
770     udpDomain.f_create_from_tstring = netsnmp_udp_create_tstring;
771     udpDomain.f_create_from_ostring = netsnmp_udp_create_ostring;
772
773     netsnmp_tdomain_register(&udpDomain);
774 }