Add IPv6 transport for bsnmp.

This patch adds a new table begemotSnmpdTransInetTable that uses the
InetAddressType textual convention and can be used to create listening
ports for IPv4, IPv6, zoned IPv6 and based on DNS names. It also supports
future extension beyond UDP by adding a protocol identifier to the table
index. In order to support this gensnmptree had to be modified.

Submitted by:   harti
MFC after:      1 month
Relnotes:       yes
Differential Revision:  https://reviews.freebsd.org/D16654
This commit is contained in:
Andrey V. Elsukov 2019-04-02 12:50:01 +00:00
parent a8cb655d2e
commit 04d1781439
18 changed files with 2278 additions and 298 deletions

View File

@ -31,7 +31,7 @@
.\"
.\" $Begemot: gensnmptree.1 383 2006-05-30 07:40:49Z brandt_h $
.\"
.Dd June 29, 2018
.Dd April 2, 2019
.Dt GENSNMPTREE 1
.Os
.Sh NAME
@ -100,25 +100,11 @@ is the length of the OID.
is the last component of the OID.
.El
.It Fl F
Together with
.Fl E
causes
.Nm
instead of the generation of enum definitions the generation of
functions for checking a value to be one of the enumeration variants and
for conversion between strings and the enum. The file is sent to standard
output and is meant to be included into a C-file for compilation.
emit definitions for C-functions includeable in a C-file that do some basic
stuff on enums like value checking and conversion between value and strings.
.It Fl f
This flag can be used together with
.Fl E
or when generating the tree files. It causes
.Nm
to emit static inline functions for checking a value to be one of the
enumeration values and for conversion between strings and the enum.
If used when generating the tree files, the preprocessor symbol
.Ar SNMPTREE_TYPES
must be defined when including the tree header file for these definitions
to become visible.
emit definitions for inline C-functions that do some basic
stuff on enums like value checking and conversion between value and strings.
.It Fl h
Print a short help page.
.It Fl I Ar directory
@ -136,36 +122,6 @@ Instead of normal output print the resulting tree.
Prefix the file names and the table name with
.Ar prefix .
.El
.Pp
The following functions are generated by
.Fl f
or
.Fl F :
.Pp
.Ft static inline int
.Fn isok_EnumName "enum EnumName" ;
.Pp
.Ft static inline const char *
.Fn tostr_EnumName "enum EnumName" ;
.Pp
.Ft static inline int
.Fn fromstr_EnumName "const char *" "enum EnumName *" ;
.Pp
The
.Fa EnumName
is replaced with the enumeration name.
.Fn isok_EnumName
returns 1 if the argument is one of the valid enum values and 0 otherwise.
.Fn tostr_EnumName
returns a string representation of the enumeration value.
If the values is not one of the legal values
.Ar EnumName???
is returned.
.Fn fromstr_EnumName
returns 1 if the string represents one of the legal enumeration values and
0 otherwise.
If 1 is return the variable pointed to by the second argument is set to
the enumeration value.
.Sh MIBS
The syntax of the MIB description file can formally be specified as follows:
.Bd -unfilled -offset indent

View File

@ -110,7 +110,6 @@ static int debug;
static const char usgtxt[] = "\
Generate SNMP tables.\n\
$Id$\n\
usage: gensnmptree [-dEeFfhlt] [-I directory] [-i infile] [-p prefix]\n\
[name]...\n\
options:\n\
@ -127,6 +126,37 @@ options:\n\
-t generate a .def file\n\
";
/**
* Program operation.
*/
enum op {
/** generate the tree */
OP_GEN,
/** extract OIDs */
OP_EXTRACT,
/** print the parsed tree */
OP_TREE,
/** extract enums */
OP_ENUMS,
};
/**
* Which functions to create.
*/
enum gen_funcs {
/** none */
GEN_FUNCS_NONE,
/** functions for header files */
GEN_FUNCS_H,
/** functions for C files */
GEN_FUNCS_C,
};
/*
* A node in the OID tree
*/
@ -162,15 +192,18 @@ struct node {
uint32_t index; /* index for table entry */
char *func; /* function for tables */
struct node_list subs;
char *subtypes[SNMP_INDEXES_MAX];
} entry;
struct leaf {
enum snmp_syntax syntax; /* syntax for this leaf */
char *func; /* function name */
char *subtype; /* subtype */
} leaf;
struct column {
enum snmp_syntax syntax; /* syntax for this column */
char *subtype; /* subtype */
} column;
} u;
};
@ -214,7 +247,7 @@ xalloc(size_t size)
{
void *ptr;
if ((ptr = malloc(size)) == NULL)
if ((ptr = calloc(1, size)) == NULL)
err(1, "allocing %zu bytes", size);
return (ptr);
@ -710,12 +743,14 @@ make_type(const char *s)
* token.
*/
static u_int
parse_type(enum tok *tok, struct type *t, const char *vname)
parse_type(enum tok *tok, struct type *t, const char *vname, char **subtype)
{
u_int syntax;
struct enums *e;
syntax = val;
if (subtype != NULL)
*subtype = NULL;
if (*tok == TOK_ENUM || *tok == TOK_BITS) {
if (t == NULL && vname != NULL) {
@ -759,6 +794,8 @@ parse_type(enum tok *tok, struct type *t, const char *vname)
if ((*tok = gettoken()) == '|') {
if (gettoken() != TOK_STR)
report("subtype expected after '|'");
if (subtype != NULL)
*subtype = savetok();
*tok = gettoken();
}
}
@ -794,18 +831,21 @@ parse(enum tok tok)
if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE ||
tok == TOK_ENUM || tok == TOK_BITS) {
/* LEAF or COLUM */
u_int syntax = parse_type(&tok, NULL, node->name);
char *subtype;
u_int syntax = parse_type(&tok, NULL, node->name, &subtype);
if (tok == TOK_STR) {
/* LEAF */
node->type = NODE_LEAF;
node->u.leaf.func = savetok();
node->u.leaf.syntax = syntax;
node->u.leaf.subtype = subtype;
tok = gettoken();
} else {
/* COLUMN */
node->type = NODE_COLUMN;
node->u.column.syntax = syntax;
node->u.column.subtype = subtype;
}
while (tok != ')') {
@ -825,9 +865,12 @@ parse(enum tok tok)
tok = gettoken();
while (tok == TOK_TYPE || tok == TOK_DEFTYPE ||
tok == TOK_ENUM || tok == TOK_BITS) {
u_int syntax = parse_type(&tok, NULL, node->name);
if (index_count++ == SNMP_INDEXES_MAX)
char *subtype;
u_int syntax = parse_type(&tok, NULL, node->name,
&subtype);
if (index_count == SNMP_INDEXES_MAX)
report("too many table indexes");
node->u.entry.subtypes[index_count++] = subtype;
node->u.entry.index |=
syntax << (SNMP_INDEX_SHIFT * index_count);
}
@ -882,7 +925,8 @@ parse_top(enum tok tok)
tok = gettoken();
t->is_enum = (tok == TOK_ENUM);
t->is_bits = (tok == TOK_BITS);
t->syntax = parse_type(&tok, t, NULL);
t->syntax = parse_type(&tok, t, NULL, NULL);
pushback(tok);
return (NULL);
@ -903,7 +947,7 @@ parse_top(enum tok tok)
* Generate the C-code table part for one node.
*/
static void
gen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx,
gen_node(FILE *fp, const struct node *np, struct asn_oid *oid, u_int idx,
const char *func)
{
u_int n;
@ -1008,7 +1052,7 @@ gen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx,
* Generate the header file with the function declarations.
*/
static void
gen_header(FILE *fp, struct node *np, u_int oidlen, const char *func)
gen_header(FILE *fp, const struct node *np, u_int oidlen, const char *func)
{
char f[MAXSTR + 4];
struct node *sub;
@ -1058,7 +1102,7 @@ gen_header(FILE *fp, struct node *np, u_int oidlen, const char *func)
* Generate the OID table.
*/
static void
gen_table(FILE *fp, struct node *node)
gen_table(FILE *fp, const struct node *node)
{
struct asn_oid oid;
@ -1067,7 +1111,6 @@ gen_table(FILE *fp, struct node *node)
#ifdef HAVE_STDINT_H
fprintf(fp, "#include <stdint.h>\n");
#endif
fprintf(fp, "#include <string.h>\n");
if (localincs) {
fprintf(fp, "#include \"asn1.h\"\n");
fprintf(fp, "#include \"snmp.h\"\n");
@ -1118,6 +1161,8 @@ gen_tree(const struct node *np, int level)
case NODE_LEAF:
print_syntax(np->u.leaf.syntax);
if (np->u.leaf.subtype != NULL)
printf(" | %s", np->u.leaf.subtype);
printf(" %s%s%s)\n", np->u.leaf.func,
(np->flags & FL_GET) ? " GET" : "",
(np->flags & FL_SET) ? " SET" : "");
@ -1137,8 +1182,11 @@ gen_tree(const struct node *np, int level)
case NODE_ENTRY:
printf(" :");
for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++)
for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) {
print_syntax(SNMP_INDEX(np->u.entry.index, i));
if (np->u.entry.subtypes[i] != NULL)
printf(" | %s", np->u.entry.subtypes[i]);
}
printf(" %s\n", np->u.entry.func);
TAILQ_FOREACH(sp, &np->u.entry.subs, link)
gen_tree(sp, level + 1);
@ -1147,6 +1195,8 @@ gen_tree(const struct node *np, int level)
case NODE_COLUMN:
print_syntax(np->u.column.syntax);
if (np->u.column.subtype != NULL)
printf(" | %s", np->u.column.subtype);
printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "",
(np->flags & FL_SET) ? " SET" : "");
break;
@ -1194,15 +1244,6 @@ extract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj,
return (1);
}
/**
* Extract the named OID.
*
* \param fp file to extract to
* \param root root of the tree
* \param object name of the object to extract
*
* \return 0 on success, -1 if the object was not found
*/
static int
gen_extract(FILE *fp, const struct node *root, char *object)
{
@ -1390,45 +1431,6 @@ unminus(FILE *fp, const char *s)
}
}
/**
* Generate a definition for the enum packed into a guard against multiple
* definitions.
*
* \param fp file to write definition to
* \param t type
*/
static void
gen_enum(FILE *fp, const struct type *t)
{
const struct enums *e;
long min = LONG_MAX;
fprintf(fp, "\n");
fprintf(fp, "#ifndef %s_defined__\n", t->name);
fprintf(fp, "#define %s_defined__\n", t->name);
fprintf(fp, "/*\n");
fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno);
fprintf(fp, " */\n");
fprintf(fp, "enum %s {\n", t->name);
TAILQ_FOREACH(e, &t->enums, link) {
fprintf(fp, "\t%s_", t->name);
unminus(fp, e->name);
fprintf(fp, " = %ld,\n", e->value);
if (e->value < min)
min = e->value;
}
fprintf(fp, "};\n");
fprintf(fp, "#define STROFF_%s %ld\n", t->name, min);
fprintf(fp, "#define STRING_%s \\\n", t->name);
TAILQ_FOREACH(e, &t->enums, link) {
fprintf(fp, "\t[%ld] = \"%s_", e->value - min, t->name);
unminus(fp, e->name);
fprintf(fp, "\",\\\n");
}
fprintf(fp, "\n");
fprintf(fp, "#endif /* %s_defined__ */\n", t->name);
}
/**
* Generate helper functions for an enum.
*
@ -1493,6 +1495,54 @@ gen_enum_funcs(FILE *fp, const struct type *t, int ccode)
fprintf(fp, "}\n");
}
/**
* Generate a definition for the enum packed into a guard against multiple
* definitions.
*
* \param fp file to write definition to
* \param t type
* \param dof generate functions too
*/
static void
gen_enum(FILE *fp, const struct type *t, int dof)
{
const struct enums *e;
long min = LONG_MAX;
fprintf(fp, "\n");
fprintf(fp, "#ifndef %s_defined__\n", t->name);
fprintf(fp, "#define %s_defined__\n", t->name);
fprintf(fp, "/*\n");
fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno);
fprintf(fp, " */\n");
fprintf(fp, "enum %s {\n", t->name);
TAILQ_FOREACH(e, &t->enums, link) {
fprintf(fp, "\t%s_", t->name);
unminus(fp, e->name);
fprintf(fp, " = %ld,\n", e->value);
if (e->value < min)
min = e->value;
}
fprintf(fp, "};\n");
fprintf(fp, "#define STROFF_%s %ld\n", t->name, min);
fprintf(fp, "#define STRING_%s \\\n", t->name);
TAILQ_FOREACH(e, &t->enums, link) {
fprintf(fp, "\t[%ld] = \"%s_", e->value - min, t->name);
unminus(fp, e->name);
fprintf(fp, "\",\\\n");
}
fprintf(fp, "\n");
if (dof) {
fprintf(fp, "#ifdef SNMPENUM_FUNCS\n");
fprintf(fp, "\n");
gen_enum_funcs(fp, t, 0);
fprintf(fp, "\n");
fprintf(fp, "#endif\n");
fprintf(fp, "\n");
}
fprintf(fp, "#endif /* %s_defined__ */\n", t->name);
}
/**
* Generate helper functions for an enum. This generates code for a c file.
*
@ -1529,6 +1579,16 @@ gen_all_enum_funcs(FILE *fp, int ccode)
gen_enum_funcs(fp, t, ccode);
}
static void
gen_enums(FILE *fp, int dof)
{
const struct type *t;
LIST_FOREACH(t, &types, link)
if (t->is_enum || t->is_bits)
gen_enum(fp, t, dof);
}
/**
* Extract a given enum to the specified file and optionally generate static
* inline helper functions for them.
@ -1546,9 +1606,7 @@ extract_enum(FILE *fp, const char *name, int gen_funcs)
LIST_FOREACH(t, &types, link)
if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) {
gen_enum(fp, t);
if (gen_funcs)
gen_enum_funcs(fp, t, 0);
gen_enum(fp, t, gen_funcs);
return (0);
}
return (-1);
@ -1567,11 +1625,8 @@ extract_all_enums(FILE *fp, int gen_funcs)
const struct type *t;
LIST_FOREACH(t, &types, link)
if (t->is_enum || t->is_bits) {
gen_enum(fp, t);
if (gen_funcs)
gen_enum_funcs(fp, t, 0);
}
if (t->is_enum || t->is_bits)
gen_enum(fp, t, gen_funcs);
}
/**
@ -1579,13 +1634,12 @@ extract_all_enums(FILE *fp, int gen_funcs)
*
* \param argc number of arguments
* \param argv arguments (enum names)
* \param gen_funcs_h generate functions into the header file
* \param gen_funcs_c generate a .c file with functions
* \param gen_funcs which functions to generate
*/
static void
make_enums(int argc, char *argv[], int gen_funcs_h, int gen_funcs_c)
make_enums(int argc, char *argv[], enum gen_funcs gen_funcs)
{
if (gen_funcs_c) {
if (gen_funcs == GEN_FUNCS_C) {
if (argc == 0)
gen_all_enum_funcs(stdout, 1);
else {
@ -1595,30 +1649,58 @@ make_enums(int argc, char *argv[], int gen_funcs_h, int gen_funcs_c)
}
} else {
if (argc == 0)
extract_all_enums(stdout, gen_funcs_h);
extract_all_enums(stdout, gen_funcs == GEN_FUNCS_H);
else {
for (int i = 0; i < argc; i++)
if (extract_enum(stdout, argv[i], gen_funcs_h))
if (extract_enum(stdout, argv[i],
gen_funcs == GEN_FUNCS_H))
errx(1, "enum not found: %s", argv[i]);
}
}
}
/**
* Produce the operation tables for the daemon or a module.
*
* \param root tree root
* \param gen_funcs generate enum funcs
*/
static void
make_table(const struct node *root, int gen_funcs)
{
FILE *fp;
char fname[MAXPATHLEN + 1];
sprintf(fname, "%stree.h", file_prefix);
if ((fp = fopen(fname, "w")) == NULL)
err(1, "%s: ", fname);
gen_header(fp, root, PREFIX_LEN, NULL);
fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n");
gen_enums(fp, gen_funcs);
fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n");
fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size);
fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix);
fclose(fp);
sprintf(fname, "%stree.c", file_prefix);
if ((fp = fopen(fname, "w")) == NULL)
err(1, "%s: ", fname);
gen_table(fp, root);
fclose(fp);
}
int
main(int argc, char *argv[])
{
int do_extract = 0;
int do_tree = 0;
int do_enums = 0;
int gen_funcs_h = 0;
int gen_funcs_c = 0;
int opt;
struct node *root;
char fname[MAXPATHLEN + 1];
int tok;
FILE *fp;
enum op op = OP_GEN;
enum gen_funcs gen_funcs = GEN_FUNCS_NONE;
char *infile = NULL;
int opt;
while ((opt = getopt(argc, argv, "dEeFfhI:i:lp:t")) != EOF)
switch (opt) {
@ -1627,19 +1709,29 @@ main(int argc, char *argv[])
break;
case 'E':
do_enums = 1;
if (op != OP_GEN && op != OP_ENUMS)
errx(1, "-E conflicts with earlier options");
op = OP_ENUMS;
break;
case 'e':
do_extract = 1;
if (op != OP_GEN && op != OP_EXTRACT)
errx(1, "-e conflicts with earlier options");
op = OP_EXTRACT;
break;
case 'F':
gen_funcs_c = 1;
if (gen_funcs != GEN_FUNCS_NONE &&
gen_funcs != GEN_FUNCS_C)
errx(1, "-F conflicts with -f");
gen_funcs = GEN_FUNCS_C;
break;
case 'f':
gen_funcs_h = 1;
if (gen_funcs != GEN_FUNCS_NONE &&
gen_funcs != GEN_FUNCS_H)
errx(1, "-f conflicts with -F");
gen_funcs = GEN_FUNCS_H;
break;
case 'h':
@ -1666,75 +1758,61 @@ main(int argc, char *argv[])
break;
case 't':
do_tree = 1;
if (op != OP_GEN && op != OP_TREE)
errx(1, "-t conflicts with earlier options");
op = OP_TREE;
break;
}
if (do_extract + do_tree + do_enums > 1)
errx(1, "conflicting options -e/-t/-E");
if (!do_extract && !do_enums && argc != optind)
errx(1, "no arguments allowed");
if (do_extract && argc == optind)
errx(1, "no objects specified");
if ((gen_funcs_h || gen_funcs_c) && (do_extract || do_tree))
errx(1, "-f and -F not allowed with -e or -t");
if (gen_funcs_c && !do_enums)
errx(1, "-F requires -E");
if (gen_funcs_h && gen_funcs_c)
errx(1, "-f and -F are mutually exclusive");
argc -= optind;
argv += optind;
/* open input */
if (infile == NULL) {
input_new(stdin, NULL, "<stdin>");
} else {
FILE *fp;
if ((fp = fopen(infile, "r")) == NULL)
err(1, "%s", infile);
input_new(fp, NULL, infile);
}
root = parse_top(gettoken());
/* parse and check input */
struct node *root = parse_top(gettoken());
int tok;
while ((tok = gettoken()) != TOK_EOF)
merge(&root, parse_top(tok));
if (root)
check_tree(root);
if (do_extract) {
while (optind < argc) {
if (gen_extract(stdout, root, argv[optind]))
errx(1, "object not found: %s", argv[optind]);
optind++;
}
/* do what the user has requested */
switch (op) {
case OP_EXTRACT:
if (argc == 0)
errx(1, "-e requires arguments");
for (int i = 0; i < argc; i++)
if (gen_extract(stdout, root, argv[i]))
errx(1, "object not found: %s", argv[i]);
return (0);
}
if (do_enums) {
make_enums(argc - optind, argv + optind,
gen_funcs_h, gen_funcs_c);
case OP_ENUMS:
make_enums(argc, argv, gen_funcs);
return (0);
}
if (do_tree) {
case OP_TREE:
if (argc != 0)
errx(1, "-t allows no arguments");
gen_tree(root, 0);
return (0);
}
sprintf(fname, "%stree.h", file_prefix);
if ((fp = fopen(fname, "w")) == NULL)
err(1, "%s: ", fname);
gen_header(fp, root, PREFIX_LEN, NULL);
fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n");
extract_all_enums(fp, gen_funcs_h);
fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n");
fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size);
fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix);
fclose(fp);
sprintf(fname, "%stree.c", file_prefix);
if ((fp = fopen(fname, "w")) == NULL)
err(1, "%s: ", fname);
gen_table(fp, root);
fclose(fp);
case OP_GEN:
if (argc != 0)
errx(1, "tree generation allows no arguments");
make_table(root, gen_funcs == GEN_FUNCS_H);
return (0);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2005
* Copyright (c) 2004-2005,2018
* Hartmut Brandt.
* All rights reserved.
* Copyright (c) 2001-2003
@ -34,11 +34,13 @@
*
* Support functions for SNMP clients.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <net/if.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@ -58,12 +60,16 @@
#include <err.h>
#endif
#include <arpa/inet.h>
#include "support.h"
#include "asn1.h"
#include "snmp.h"
#include "snmpclient.h"
#include "snmppriv.h"
#define DEBUG_PARSE 0
/* global context */
struct snmp_client snmp_client;
@ -924,7 +930,8 @@ open_client_udp(const char *host, const char *port)
/* open connection */
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_INET;
hints.ai_family = snmp_client.trans == SNMP_TRANS_UDP ? AF_INET:
AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
error = getaddrinfo(snmp_client.chost, snmp_client.cport, &hints, &res0);
@ -1068,6 +1075,7 @@ snmp_open(const char *host, const char *port, const char *readcomm,
switch (snmp_client.trans) {
case SNMP_TRANS_UDP:
case SNMP_TRANS_UDP6:
if (open_client_udp(host, port) != 0)
return (-1);
break;
@ -1866,99 +1874,410 @@ snmp_client_set_port(struct snmp_client *cl, const char *p)
return (0);
}
/*
* parse a server specification
/**
* Try to get a transport identifier which is a leading alphanumeric string
* (starting with '_' or a letter and including also '_') terminated by
* a double colon. The string may not be empty. The transport identifier
* is optional.
*
* [trans::][community@][server][:port]
* \param sc client struct to set errors
* \param strp possible start of transport; updated to point to
* the next character to parse
*
* \return end of transport; equals *strp if there is none; NULL if there
* was an error
*/
static inline const char *
get_transp(struct snmp_client *sc, const char **strp)
{
const char *p = *strp;
if (isascii(*p) && (isalpha(*p) || *p == '_')) {
p++;
while (isascii(*p) && (isalnum(*p) || *p == '_'))
p++;
if (p[0] == ':' && p[1] == ':') {
*strp = p + 2;
return (p);
}
}
if (p[0] == ':' && p[1] == ':') {
seterr(sc, "empty transport specifier");
return (NULL);
}
return (*strp);
}
/**
* Try to get community string. Eat everything up to the last @ (if there is
* any) but only if it is not longer than SNMP_COMMUNITY_MAXLEN. Empty
* community strings are legal.
*
* \param sc client struct to set errors
* \param strp possible start of community; updated to the point to
* the next character to parse
*
* \return end of community; equals *strp if there is none; NULL if there
* was an error
*/
static inline const char *
get_comm(struct snmp_client *sc, const char **strp)
{
const char *p = strrchr(*strp, '@');
if (p == NULL)
/* no community string */
return (*strp);
if (p - *strp > SNMP_COMMUNITY_MAXLEN) {
seterr(sc, "community string too long '%.*s'",
p - *strp, *strp);
return (NULL);
}
*strp = p + 1;
return (p);
}
/**
* Try to get an IPv6 address. This starts with an [ and should end with an ]
* and everything between should be not longer than INET6_ADDRSTRLEN and
* parseable by inet_pton().
*
* \param sc client struct to set errors
* \param strp possible start of IPv6 address (the '['); updated to point to
* the next character to parse (the one after the closing ']')
*
* \return end of address (equals *strp + 1 if there is none) or NULL
* on errors
*/
static inline const char *
get_ipv6(struct snmp_client *sc, const char **strp)
{
char str[INET6_ADDRSTRLEN + IF_NAMESIZE];
struct addrinfo hints, *res;
int error;
if (**strp != '[')
return (*strp + 1);
const char *p = *strp + 1;
while (*p != ']' ) {
if (*p == '\0') {
seterr(sc, "unterminated IPv6 address '%.*s'",
p - *strp, *strp);
return (NULL);
}
p++;
}
if (p - *strp > INET6_ADDRSTRLEN + IF_NAMESIZE) {
seterr(sc, "IPv6 address too long '%.*s'", p - *strp, *strp);
return (NULL);
}
strncpy(str, *strp + 1, p - (*strp + 1));
str[p - (*strp + 1)] = '\0';
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME | AI_NUMERICHOST;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
error = getaddrinfo(str, NULL, &hints, &res);
if (error != 0) {
seterr(sc, "%s: %s", str, gai_strerror(error));
return (NULL);
}
freeaddrinfo(res);
*strp = p + 1;
return (p);
}
/**
* Try to get an IPv4 address. This starts with a digit and consists of digits
* and dots, is not longer INET_ADDRSTRLEN and must be parseable by
* inet_aton().
*
* \param sc client struct to set errors
* \param strp possible start of IPv4 address; updated to point to the
* next character to parse
*
* \return end of address (equals *strp if there is none) or NULL
* on errors
*/
static inline const char *
get_ipv4(struct snmp_client *sc, const char **strp)
{
const char *p = *strp;
while (isascii(*p) && (isdigit(*p) || *p == '.'))
p++;
if (p - *strp > INET_ADDRSTRLEN) {
seterr(sc, "IPv4 address too long '%.*s'", p - *strp, *strp);
return (NULL);
}
if (*strp == p)
return *strp;
char str[INET_ADDRSTRLEN + 1];
strncpy(str, *strp, p - *strp);
str[p - *strp] = '\0';
struct in_addr addr;
if (inet_aton(str, &addr) != 1) {
seterr(sc, "illegal IPv4 address '%s'", str);
return (NULL);
}
*strp = p;
return (p);
}
/**
* Try to get a hostname. This includes everything up to but not including
* the last colon (if any). There is no length restriction.
*
* \param sc client struct to set errors
* \param strp possible start of hostname; updated to point to the next
* character to parse (the trailing NUL character or the last
* colon)
*
* \return end of address (equals *strp if there is none)
*/
static inline const char *
get_host(struct snmp_client *sc __unused, const char **strp)
{
const char *p = strrchr(*strp, ':');
if (p == NULL) {
*strp += strlen(*strp);
return (*strp);
}
*strp = p;
return (p);
}
/**
* Try to get a port number. This start with a colon and extends to the end
* of string. The port number must not be empty.
*
* \param sc client struct to set errors
* \param strp possible start of port specification; if this points to a
* colon there is a port specification
*
* \return end of port number (equals *strp if there is none); NULL
* if there is no port number
*/
static inline const char *
get_port(struct snmp_client *sc, const char **strp)
{
if (**strp != ':')
return (*strp + 1);
if ((*strp)[1] == '\0') {
seterr(sc, "empty port name");
return (NULL);
}
*strp += strlen(*strp);
return (*strp);
}
/**
* Save the string in the range given by two pointers.
*
* \param sc client struct to set errors
* \param s begin and end pointers
*
* \return freshly allocated copy of the string between s[0] and s[1]
*/
static inline char *
save_str(struct snmp_client *sc, const char *const s[2])
{
char *m;
if ((m = malloc(s[1] - s[0] + 1)) == NULL) {
seterr(sc, "%s: %s", __func__, strerror(errno));
return (NULL);
}
strncpy(m, s[0], s[1] - s[0]);
m[s[1] - s[0]] = '\0';
return (m);
}
/**
* Parse a server specification. All parts are optional:
*
* [<trans>::][<comm>@][<host-or-ip>][:<port>]
*
* The transport string consists of letters, digits or '_' and starts with
* a letter or digit. It is terminated by two colons and may not be empty.
*
* The community string is terminated by the last '@' and does not exceed
* SNMP_COMMUNITY_MAXLEN. It may be empty.
*
* The host or ip is either an IPv4 address (as parsed by inet_pton()), an
* IPv6 address in '[' and ']' and parseable by inet_aton() or a hostname
* terminated by the last colon or by the NUL character.
*
* The port number may be specified numerically or symbolically and starts
* with the last colon.
*
* The functions sets the chost, cport, trans, read_community and
* write_community fields on success and the error field on errors.
* The chost and cport fields are allocated by malloc(3), their previous
* content is deallocated by free(3).
*
* The function explicitly allows mismatches between the transport and
* the address type in order to support IPv4 in IPv6 addresses.
*
* \param sc client struct to fill
* \param str string to parse
*
* \return 0 on success and -1 on errors
*/
int
snmp_parse_server(struct snmp_client *sc, const char *str)
{
const char *p, *s = str;
#if DEBUG_PARSE
const char *const orig = str;
#endif
/* look for a double colon */
for (p = s; *p != '\0'; p++) {
if (*p == '\\' && p[1] != '\0') {
p++;
continue;
const char *const trans_list[] = {
[SNMP_TRANS_UDP] = "udp",
[SNMP_TRANS_LOC_DGRAM] = "dgram",
[SNMP_TRANS_LOC_STREAM] = "stream",
[SNMP_TRANS_UDP6] = "udp6",
};
/* parse input */
const char *const transp[2] = {
str,
get_transp(sc, &str),
};
if (transp[1] == NULL)
return (-1);
const char *const comm[2] = {
str,
get_comm(sc, &str),
};
if (comm[1] == NULL)
return (-1);
const char *const ipv6[2] = {
str + 1,
get_ipv6(sc, &str),
};
if (ipv6[1] == NULL)
return (-1);
const char *ipv4[2] = {
str,
str,
};
const char *host[2] = {
str,
str,
};
if (ipv6[0] == ipv6[1]) {
ipv4[1] = get_ipv4(sc, &str);
if (ipv4[0] == ipv4[1])
host[1] = get_host(sc, &str);
}
if (*p == ':' && p[1] == ':')
const char *port[2] = {
str + 1,
get_port(sc, &str),
};
if (port[1] == NULL)
return (-1);
if (*str != '\0') {
seterr(sc, "junk at end of server specification '%s'", str);
return (-1);
}
#if DEBUG_PARSE
printf("transp: %zu %zu\n", transp[0] - orig, transp[1] - orig);
printf("comm: %zu %zu\n", comm[0] - orig, comm[1] - orig);
printf("ipv6: %zu %zu\n", ipv6[0] - orig, ipv6[1] - orig);
printf("ipv4: %zu %zu\n", ipv4[0] - orig, ipv4[1] - orig);
printf("host: %zu %zu\n", host[0] - orig, host[1] - orig);
printf("port: %zu %zu\n", port[0] - orig, port[1] - orig);
#endif
/* analyse and allocate */
int i = -1;
if (transp[0] != transp[1]) {
for (i = 0; i < (int)nitems(trans_list); i++) {
if (trans_list[i] != NULL &&
strlen(trans_list[i]) == (size_t)(transp[1] -
transp[0]) && !strncmp(trans_list[i], transp[0],
transp[1] - transp[0]))
break;
}
if (*p != '\0') {
if (p > s) {
if (p - s == 3 && strncmp(s, "udp", 3) == 0)
sc->trans = SNMP_TRANS_UDP;
else if (p - s == 6 && strncmp(s, "stream", 6) == 0)
sc->trans = SNMP_TRANS_LOC_STREAM;
else if (p - s == 5 && strncmp(s, "dgram", 5) == 0)
sc->trans = SNMP_TRANS_LOC_DGRAM;
else {
seterr(sc, "unknown SNMP transport '%.*s'",
(int)(p - s), s);
if (i == (int)nitems(trans_list)) {
seterr(sc, "unknown transport specifier '%.*s'",
transp[1] - transp[0], transp[0]);
return (-1);
}
}
s = p + 2;
}
/* look for a @ */
for (p = s; *p != '\0'; p++) {
if (*p == '\\' && p[1] != '\0') {
p++;
continue;
}
if (*p == '@')
char *chost;
if (ipv6[0] != ipv6[1]) {
if ((chost = save_str(sc, ipv6)) == NULL)
return (-1);
if (i == -1)
i = SNMP_TRANS_UDP6;
} else if (ipv4[0] != ipv4[1]) {
if ((chost = save_str(sc, ipv4)) == NULL)
return (-1);
if (i == -1)
i = SNMP_TRANS_UDP;
} else {
if ((chost = save_str(sc, host)) == NULL)
return (-1);
if (i == -1) {
/* Default transport is UDP unless the host contains
* a slash in which case we default to DGRAM. */
i = SNMP_TRANS_UDP;
for (const char *p = host[0]; p < host[1]; p++)
if (*p == '/') {
i = SNMP_TRANS_LOC_DGRAM;
break;
}
}
}
if (*p != '\0') {
if (p - s > SNMP_COMMUNITY_MAXLEN) {
seterr(sc, "community string too long");
char *cport = save_str(sc, port);
if (cport == NULL) {
free(chost);
return (-1);
}
strncpy(sc->read_community, s, p - s);
sc->read_community[p - s] = '\0';
strncpy(sc->write_community, s, p - s);
sc->write_community[p - s] = '\0';
s = p + 1;
}
/* look for a colon */
for (p = s; *p != '\0'; p++) {
if (*p == '\\' && p[1] != '\0') {
p++;
continue;
}
if (*p == ':')
break;
}
/* commit */
sc->trans = i;
strncpy(sc->read_community, comm[0], comm[1] - comm[0]);
sc->read_community[comm[1] - comm[0]] = '\0';
strncpy(sc->write_community, comm[0], comm[1] - comm[0]);
sc->write_community[comm[1] - comm[0]] = '\0';
if (*p == ':') {
if (p > s) {
/* host:port */
free(sc->chost);
if ((sc->chost = malloc(p - s + 1)) == NULL) {
seterr(sc, "%s", strerror(errno));
return (-1);
}
strncpy(sc->chost, s, p - s);
sc->chost[p - s] = '\0';
}
/* port */
sc->chost = chost;
free(sc->cport);
if ((sc->cport = strdup(p + 1)) == NULL) {
seterr(sc, "%s", strerror(errno));
return (-1);
}
sc->cport = cport;
} else if (p > s) {
/* host */
free(sc->chost);
if ((sc->chost = strdup(s)) == NULL) {
seterr(sc, "%s", strerror(errno));
return (-1);
}
}
return (0);
}

View File

@ -49,6 +49,7 @@
#define SNMP_TRANS_UDP 0
#define SNMP_TRANS_LOC_DGRAM 1
#define SNMP_TRANS_LOC_STREAM 2
#define SNMP_TRANS_UDP6 3
/* type of callback function for responses
* this callback function is responsible for free() any memory associated with

View File

@ -46,3 +46,11 @@ typedef StorageType ENUM (
5 readOnly
)
typedef InetAddressType ENUM (
0 unknown
1 ipv4
2 ipv6
3 ipv4z
4 ipv6z
16 dns
)

View File

@ -3,6 +3,10 @@
-- Fraunhofer Institute for Open Communication Systems (FhG Fokus).
-- All rights reserved.
--
-- Copyright (c) 2018
-- Hartmut Brandt.
-- All rights reserved.
--
-- Author: Harti Brandt <harti@freebsd.org>
--
-- Redistribution and use in source and binary forms, with or without
@ -34,17 +38,17 @@ BEGEMOT-SNMPD-MIB DEFINITIONS ::= BEGIN
IMPORTS
MODULE-IDENTITY, OBJECT-TYPE, OBJECT-IDENTITY, Counter32,
Unsigned32, IpAddress
Integer32, Unsigned32, IpAddress
FROM SNMPv2-SMI
TEXTUAL-CONVENTION, TruthValue, RowStatus
FROM SNMPv2-TC
MODULE-COMPLIANCE, OBJECT-GROUP
FROM SNMPv2-CONF
InetAddressType, InetAddress, InetPortNumber
FROM INET-ADDRESS-MIB
begemot
FROM BEGEMOT-MIB;
begemotSnmpd MODULE-IDENTITY
LAST-UPDATED "201801190000Z"
LAST-UPDATED "201808080000Z"
ORGANIZATION "Fraunhofer FOKUS, CATS"
CONTACT-INFO
" Hartmut Brandt
@ -59,6 +63,9 @@ begemotSnmpd MODULE-IDENTITY
E-mail: harti@freebsd.org"
DESCRIPTION
"The MIB module for the Begemot SNMP daemon."
REVISION "201808080000Z"
DESCRIPTION
"Add the begemotSnmpdTransInetTable."
::= { begemot 1 }
begemotSnmpdObjects OBJECT IDENTIFIER ::= { begemotSnmpd 1 }
@ -93,7 +100,7 @@ begemotSnmpdAgentFreeBSD OBJECT-IDENTITY
begemotSnmpdConfig OBJECT IDENTIFIER ::= { begemotSnmpdObjects 1 }
begemotSnmpdTransmitBuffer OBJECT-TYPE
SYNTAX INTEGER (484..65535)
SYNTAX Integer32 (484..65535)
MAX-ACCESS read-write
STATUS current
DESCRIPTION
@ -103,7 +110,7 @@ begemotSnmpdTransmitBuffer OBJECT-TYPE
::= { begemotSnmpdConfig 1 }
begemotSnmpdReceiveBuffer OBJECT-TYPE
SYNTAX INTEGER (484..65535)
SYNTAX Integer32 (484..65535)
MAX-ACCESS read-write
STATUS current
DESCRIPTION
@ -181,7 +188,7 @@ begemotTrapSinkAddr OBJECT-TYPE
::= { begemotTrapSinkEntry 1 }
begemotTrapSinkPort OBJECT-TYPE
SYNTAX INTEGER (1..65535)
SYNTAX Integer32 (1..65535)
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
@ -203,7 +210,7 @@ begemotTrapSinkStatus OBJECT-TYPE
begemotSnmpdPortTable OBJECT-TYPE
SYNTAX SEQUENCE OF BegemotSnmpdPortEntry
MAX-ACCESS not-accessible
STATUS current
STATUS deprecated
DESCRIPTION
"A table with descriptions of UDP ports to listen on
for SNMP messages."
@ -212,7 +219,7 @@ begemotSnmpdPortTable OBJECT-TYPE
begemotSnmpdPortEntry OBJECT-TYPE
SYNTAX BegemotSnmpdPortEntry
MAX-ACCESS not-accessible
STATUS current
STATUS deprecated
DESCRIPTION
"An entry in the table with descriptions of UDP ports to
listen on for SNMP messages."
@ -228,15 +235,15 @@ BegemotSnmpdPortEntry ::= SEQUENCE {
begemotSnmpdPortAddress OBJECT-TYPE
SYNTAX IpAddress
MAX-ACCESS not-accessible
STATUS current
STATUS deprecated
DESCRIPTION
"The IP address to bind to."
::= { begemotSnmpdPortEntry 1 }
begemotSnmpdPortPort OBJECT-TYPE
SYNTAX INTEGER (1..65535)
SYNTAX Integer32 (1..65535)
MAX-ACCESS not-accessible
STATUS current
STATUS deprecated
DESCRIPTION
"The UDP port to listen on for SNMP messages."
::= { begemotSnmpdPortEntry 2 }
@ -244,7 +251,7 @@ begemotSnmpdPortPort OBJECT-TYPE
begemotSnmpdPortStatus OBJECT-TYPE
SYNTAX INTEGER { valid(1), invalid(2) }
MAX-ACCESS read-create
STATUS current
STATUS deprecated
DESCRIPTION
"Set status to 1 to create entry, set it to 2 to delete it."
::= { begemotSnmpdPortEntry 3 }
@ -275,7 +282,7 @@ BegemotSnmpdCommunityEntry ::= SEQUENCE {
begemotSnmpdCommunityIndex Unsigned32,
begemotSnmpdCommunityString OCTET STRING,
begemotSnmpdCommunityDescr OCTET STRING,
begemotSnmpdCommunityPermission INTEGER
begemotSnmpdCommunityPermission Unsigned32
}
begemotSnmpdCommunityModule OBJECT-TYPE
@ -312,7 +319,7 @@ begemotSnmpdCommunityDescr OBJECT-TYPE
::= { begemotSnmpdCommunityEntry 4 }
begemotSnmpdCommunityPermission OBJECT-TYPE
SYNTAX INTEGER (1..4294967295)
SYNTAX Unsigned32 (1..4294967295)
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
@ -449,7 +456,7 @@ begemotSnmpdDebugSnmpTrace OBJECT-TYPE
::= { begemotSnmpdDebug 2 }
begemotSnmpdDebugSyslogPri OBJECT-TYPE
SYNTAX INTEGER (0..8)
SYNTAX Integer32 (0..8)
MAX-ACCESS read-write
STATUS current
DESCRIPTION
@ -570,10 +577,115 @@ begemotSnmpdTransportOid OBJECT-TYPE
"A pointer to the group with the transport-dependend stuff."
::= { begemotSnmpdTransportEntry 3 }
-- ----------------------------------------------------------------------
--
-- Internet port table.
--
BegemotSnmpdTransportProto ::= TEXTUAL-CONVENTION
STATUS current
DESCRIPTION
"A value that represents the type of protocol to be used for
listening on a socket. The following protocols are currently
used:
udp(1) Use UDP for IPv4 and IPv6 sockets."
SYNTAX INTEGER {
udp(1)
}
begemotSnmpdTransInetTable OBJECT-TYPE
SYNTAX SEQUENCE OF BegemotSnmpdTransInetEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"This table contains all the ports the daemon should listen on.
Entries can be created at initialization time via the config
file or at run time via a SET. One row can map to several open
sockets in the case of InetAddressType::dns rows. These rows
open one socket for each address returned by getaddrinfo(3).
for SNMP messages."
::= { begemotSnmpdObjects 11 }
begemotSnmpdTransInetEntry OBJECT-TYPE
SYNTAX BegemotSnmpdTransInetEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"A row of the internet port table. Each row may map to one or
more listening sockets."
INDEX {
begemotSnmpdTransInetAddressType,
begemotSnmpdTransInetAddress,
begemotSnmpdTransInetPort,
begemotSnmpdTransInetProto
}
::= { begemotSnmpdTransInetTable 1 }
BegemotSnmpdTransInetEntry ::= SEQUENCE {
begemotSnmpdTransInetAddressType InetAddressType,
begemotSnmpdTransInetAddress InetAddress,
begemotSnmpdTransInetPort InetPortNumber,
begemotSnmpdTransInetProto BegemotSnmpdTransportProto,
begemotSnmpdTransInetStatus RowStatus
}
begemotSnmpdTransInetAddressType OBJECT-TYPE
SYNTAX InetAddressType
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"The type of the address. Only ipv4, ipv6, ipv6z and dns are
supported."
::= { begemotSnmpdTransInetEntry 1 }
begemotSnmpdTransInetAddress OBJECT-TYPE
SYNTAX InetAddress (SIZE (0..64))
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"The address. For ipv4 addresses the length must be 4, ipv6
addresses have a length of 16 and ipv6z addresses a length of
20 where the last four bytes are the interface index in big
endian format. dns addresses may be of zero-length in which case
getaddrinfo() generates INADDR_ANY and its IPv6 equivalent. dns
addresses will open a socket for all addresses returned by
getaddrinfo()."
::= { begemotSnmpdTransInetEntry 2 }
begemotSnmpdTransInetPort OBJECT-TYPE
SYNTAX InetPortNumber (1..65535)
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"The port to listen on for SNMP messages."
::= { begemotSnmpdTransInetEntry 3 }
begemotSnmpdTransInetProto OBJECT-TYPE
SYNTAX BegemotSnmpdTransportProto
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"The protocol to use. Currently only the value udp(1) is supported."
::= { begemotSnmpdTransInetEntry 4 }
begemotSnmpdTransInetStatus OBJECT-TYPE
SYNTAX RowStatus
MAX-ACCESS read-create
STATUS current
DESCRIPTION
"The status of the conceptual row. A row may be created using
createAndGo(4) or createAndWait(5). An inactive row can be
activated writing active(1) and an active row can be inactivated
by writing notInService(2). Finally active or inactive rows can be
deleted by writing the value destroy(6). The value of this field
will never read as notReady(3)."
::= { begemotSnmpdTransInetEntry 5 }
--
-- XXX These should go into their own MIB
--
begemotSnmpdTransUdp OBJECT IDENTIFIER ::= { begemotSnmpdTransportMappings 2 }
begemotSnmpdTransLsock OBJECT IDENTIFIER ::= { begemotSnmpdTransportMappings 3 }
begemotSnmpdTransInet OBJECT IDENTIFIER ::= { begemotSnmpdTransportMappings 4 }
END

View File

@ -65,6 +65,8 @@
#include "tree.h"
#include "oid.h"
#include "trans_inet.h"
#define PATH_PID "/var/run/%s.pid"
#define PATH_CONFIG "/etc/%s.config"
#define PATH_ENGINE "/var/%s.engine"
@ -1038,7 +1040,7 @@ snmpd_input(struct port_input *pi, struct tport *tport)
ssize_t ret, slen;
int32_t vi;
#ifdef USE_TCPWRAPPERS
char client[16];
char client[INET6_ADDRSTRLEN];
#endif
ret = tport->transport->vtab->recv(tport, pi);
@ -1184,8 +1186,12 @@ snmpd_input(struct port_input *pi, struct tport *tport)
sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
if (ferr == SNMPD_INPUT_OK) {
slen = tport->transport->vtab->send(tport, sndbuf, sndlen,
pi->peer, pi->peerlen);
if (tport->transport->vtab->send != NULL)
slen = tport->transport->vtab->send(tport, sndbuf,
sndlen, pi->peer, pi->peerlen);
else
slen = tport->transport->vtab->send2(tport, sndbuf,
sndlen, pi);
if (slen == -1)
syslog(LOG_ERR, "send*: %m");
else if ((size_t)slen != sndlen)
@ -1201,7 +1207,8 @@ snmpd_input(struct port_input *pi, struct tport *tport)
}
/*
* Send a PDU to a given port
* Send a PDU to a given port. If this is a multi-socket port, use the
* first socket.
*/
void
snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
@ -1224,7 +1231,10 @@ snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY");
if (trans->vtab->send != NULL)
len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen);
else
len = trans->vtab->send2(tp, sndbuf, sndlen, NULL);
if (len == -1)
syslog(LOG_ERR, "sendto: %m");
@ -1238,16 +1248,37 @@ snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
/*
* Close an input source
*
* \param pi input instance
*/
void
snmpd_input_close(struct port_input *pi)
{
if (pi->id != NULL)
if (pi->id != NULL) {
fd_deselect(pi->id);
if (pi->fd >= 0)
pi->id = NULL;
}
if (pi->fd >= 0) {
(void)close(pi->fd);
if (pi->buf != NULL)
pi->fd = -1;
}
if (pi->buf != NULL) {
free(pi->buf);
pi->buf = NULL;
}
}
/*
* Initialize an input source.
*
* \param pi input instance
*/
void
snmpd_input_init(struct port_input *pi)
{
pi->id = NULL;
pi->fd = -1;
pi->buf = NULL;
}
/*
@ -1633,6 +1664,8 @@ main(int argc, char *argv[])
syslog(LOG_WARNING, "cannot start UDP transport");
if (lsock_trans.start() != SNMP_ERR_NOERROR)
syslog(LOG_WARNING, "cannot start LSOCK transport");
if (inet_trans.start() != SNMP_ERR_NOERROR)
syslog(LOG_WARNING, "cannot start INET transport");
#ifdef USE_LIBBEGEMOT
if (debug.evdebug > 0)

View File

@ -72,8 +72,18 @@ begemotSnmpdCommunityString.0.1 = $(read)
begemotSnmpdCommunityDisable = 1
# open standard SNMP ports
begemotSnmpdPortStatus.[$(host)].161 = 1
begemotSnmpdPortStatus.127.0.0.1.161 = 1
# begemotSnmpdPortStatus.[$(host)].161 = 1
# begemotSnmpdPortStatus.127.0.0.1.161 = 1
# UDP over IPv4: 127.0.0.1:161
begemotSnmpdTransInetStatus.1.4.127.0.0.1.161.1 = 4
# UDP over IPv6: ::1:161
begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.161.1 = 4
# Use domain name and IPv6 link-local address with scope zone id as address
# begemotSnmpdTransInetStatus.16."localhost".161.1 = 4
# begemotSnmpdTransInetStatus.16."fe80::1%em0".161.1 = 4
# open a unix domain socket
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1

View File

@ -174,7 +174,7 @@ TAILQ_HEAD(tport_list, tport);
int snmpd_input(struct port_input *, struct tport *);
void snmpd_input_close(struct port_input *);
void snmpd_input_init(struct port_input *);
/*
* Transport domain
@ -194,6 +194,10 @@ struct transport_def {
ssize_t (*send)(struct tport *, const u_char *, size_t,
const struct sockaddr *, size_t);
ssize_t (*recv)(struct tport *, struct port_input *);
/** send via a multi-socket port */
ssize_t (*send2)(struct tport *, const u_char *, size_t,
struct port_input *);
};
struct transport {
struct asn_oid index; /* transport table index */

View File

@ -56,6 +56,48 @@
* ordering can be done either on an integer/unsigned field, an asn_oid
* or an ordering function.
*/
/*
* First set of macros is used when the link is embedded into sub-struct
* and links these sub-structs. The sub-struct must be the first field.
*
* The list is a list of the subfield types.
*/
#define INSERT_OBJECT_OID_LINK_INDEX_TYPE(PTR, LIST, LINK, INDEX, SUBF) do {\
typedef __typeof ((PTR)->SUBF) _subf_type; \
_subf_type *_lelem; \
\
TAILQ_FOREACH(_lelem, (LIST), LINK) \
if (asn_compare_oid(&_lelem->INDEX, &(PTR)->SUBF.INDEX) > 0)\
break; \
if (_lelem == NULL) \
TAILQ_INSERT_TAIL((LIST), &(PTR)->SUBF, LINK); \
else \
TAILQ_INSERT_BEFORE(_lelem, &(PTR)->SUBF, LINK); \
} while (0)
#define NEXT_OBJECT_OID_LINK_INDEX_TYPE(LIST, OID, SUB, LINK, INDEX, TYPE) ({\
__typeof (TAILQ_FIRST((LIST))) _lelem; \
\
TAILQ_FOREACH(_lelem, (LIST), LINK) \
if (index_compare(OID, SUB, &_lelem->INDEX) < 0) \
break; \
(TYPE *)(_lelem); \
})
#define FIND_OBJECT_OID_LINK_INDEX_TYPE(LIST, OID, SUB, LINK, INDEX, TYPE) ({\
__typeof (TAILQ_FIRST((LIST))) _lelem; \
\
TAILQ_FOREACH(_lelem, (LIST), LINK) \
if (index_compare(OID, SUB, &_lelem->INDEX) == 0) \
break; \
(TYPE *)(_lelem); \
})
/*
* This set of macros allows specification of the link and index name.
* The index is an OID.
*/
#define INSERT_OBJECT_OID_LINK_INDEX(PTR, LIST, LINK, INDEX) do { \
__typeof (PTR) _lelem; \
\

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2018
* Hartmut Brandt.
* All rights reserved.
*
* Author: Harti Brandt <harti@freebsd.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
*/
#ifndef trans_inet_h_1530971397
#define trans_inet_h_1530971397
/* transport declaration */
extern const struct transport_def inet_trans;
#endif

View File

@ -70,7 +70,8 @@ const struct transport_def lsock_trans = {
lsock_close_port,
lsock_init_port,
lsock_send,
lsock_recv
lsock_recv,
NULL
};
static struct transport *my_trans;

View File

@ -67,7 +67,8 @@ const struct transport_def udp_trans = {
udp_close_port,
udp_init_port,
udp_send,
udp_recv
udp_recv,
NULL
};
static struct transport *my_trans;

View File

@ -3,6 +3,10 @@
# Fraunhofer Institute for Open Communication Systems (FhG Fokus).
# All rights reserved.
#
# Copyright (c) 2018
# Hartmut Brandt.
# All rights reserved.
#
# Author: Harti Brandt <harti@freebsd.org>
#
# Redistribution and use in source and binary forms, with or without
@ -33,6 +37,10 @@
include "tc.def"
typedef BegemotSnmpdTransportProto ENUM (
1 udp
)
(1 internet
(2 mgmt
(1 mibII
@ -172,13 +180,24 @@ include "tc.def"
))
(2 begemotSnmpdTransUdp OID op_transport_dummy)
(3 begemotSnmpdTransLsock OID op_transport_dummy)
(4 begemotSnmpdTransInet OID op_transport_dummy)
)
(11 begemotSnmpdTransInetTable
(1 begemotSnmpdTransInetEntry : INTEGER OCTETSTRING INTEGER INTEGER op_snmp_trans_inet
(1 begemotSnmpdTransInetAddressType InetAddressType)
(2 begemotSnmpdTransInetAddress OCTETSTRING)
(3 begemotSnmpdTransInetPort INTEGER)
(4 begemotSnmpdTransInetProto BegemotSnmpdTransportProto)
(5 begemotSnmpdTransInetStatus RowStatus GET SET)
))
)
(2 begemotSnmpdDefs
(1 begemotSnmpdAgent
(1 begemotSnmpdAgentFreeBSD OID op_dummy)
)
)
(3 begemotSnmpdCompliance)
)
))
)

View File

@ -129,4 +129,8 @@ MLINKS+= bsnmplib.3 snmp_value_copy.3
MLINKS+= bsnmplib.3 snmp_value_free.3
MLINKS+= bsnmplib.3 snmp_value_parse.3
FILESGROUPS+= DEFS
DEFS= tc.def
DEFSDIR?= ${SHAREDIR}/snmp/defs
.include <bsd.lib.mk>

View File

@ -11,11 +11,11 @@ CONFS= snmpd.config
CONFSMODE= 600
PROG= bsnmpd
SRCS= main.c action.c config.c export.c trap.c trans_udp.c trans_lsock.c
SRCS+= oid.h tree.c tree.h
SRCS+= trans_inet.c oid.h tree.c tree.h
XSYM= snmpMIB begemotSnmpdModuleTable begemotSnmpd begemotTrapSinkTable \
sysUpTime snmpTrapOID coldStart authenticationFailure \
begemotSnmpdTransUdp begemotSnmpdTransLsock begemotSnmpdLocalPortTable \
freeBSD freeBSDVersion
freeBSD freeBSDVersion begemotSnmpdTransInet
CLEANFILES= oid.h tree.c tree.h
MAN= bsnmpd.1 snmpmod.3

View File

@ -92,10 +92,22 @@ begemotSnmpdDebugSyslogPri = 7
#
begemotSnmpdCommunityString.0.1 = $(read)
# begemotSnmpdCommunityString.0.2 = $(write)
# begemotSnmpdCommunityString.0.3 = "otherPublic"
begemotSnmpdCommunityDisable = 1
# open standard SNMP ports
begemotSnmpdPortStatus.0.0.0.0.161 = 1
begemotSnmpdTransInetStatus.1.4.0.0.0.0.161.1 = 4
begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.161.1 = 4
# UDP over IPv4: 127.0.0.1:161
# begemotSnmpdTransInetStatus.1.4.127.0.0.1.161.1 = 4
# UDP over IPv6: ::1:161
# begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.161.1 = 4
# Use domain name and IPv6 link-local address with scope zone id as address
# begemotSnmpdTransInetStatus.16."localhost".161.1 = 4
# begemotSnmpdTransInetStatus.16."fe80::1%em0".161.1 = 4
# open a unix domain socket
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1