char const *fr_app_io_socket_name(TALLOC_CTX *ctx, fr_app_io_t const *app_io, fr_ipaddr_t const *src_ipaddr, int src_port, fr_ipaddr_t const *dst_ipaddr, int dst_port) { char dst_buf[128], src_buf[128]; /* * Get our name. */ if (fr_ipaddr_is_inaddr_any(dst_ipaddr)) { if (dst_ipaddr->af == AF_INET) { strlcpy(dst_buf, "*", sizeof(dst_buf)); } else { rad_assert(dst_ipaddr->af == AF_INET6); strlcpy(dst_buf, "::", sizeof(dst_buf)); } } else { fr_value_box_snprint(dst_buf, sizeof(dst_buf), fr_box_ipaddr(*dst_ipaddr), 0); } if (!src_ipaddr) { return talloc_typed_asprintf(ctx, "proto_%s server %s port %u", app_io->name, dst_buf, dst_port); } fr_value_box_snprint(src_buf, sizeof(src_buf), fr_box_ipaddr(*src_ipaddr), 0); return talloc_typed_asprintf(ctx, "proto_%s from client %s port %u to server %s port %u", app_io->name, src_buf, src_port, dst_buf, dst_port); }
/** Write the result of a get or getnext operation back to net-snmp * * Returns three lines of output per attribute: * - OID string * - type * - value * * Index attributes (num 0) must be in order of depth (shallowest first). * * If no attributes were written, will write "NONE\n" to inform net-snmp * that no value was available at the specified OID. * * @param fd to write to. * @param root of the SNMP portion of the main dictionary. * @param type attribute. * @param head of list of attributes to convert and write. * @return * - >=0 on success (the number of varbind responses written). * - -1 on failure. */ static int radsnmp_get_response(int fd, fr_dict_attr_t const *root, fr_dict_attr_t const *type, VALUE_PAIR *head) { fr_cursor_t cursor; VALUE_PAIR *vp, *type_vp; fr_dict_attr_t const *parent = root; unsigned int written = 0; ssize_t slen; size_t len; char type_buff[32]; /* type */ size_t type_len = 0; char oid_buff[256]; char value_buff[128]; char *p = oid_buff, *end = p + sizeof(oid_buff); struct iovec io_vector[6]; char newline[] = "\n"; type_buff[0] = '\0'; /* * Print first part of OID string. */ slen = snprintf(oid_buff, sizeof(oid_buff), "%u.", parent->attr); if (is_truncated((size_t)slen, sizeof(oid_buff))) { oob: fr_strerror_printf("OID Buffer too small"); return -1; } p += slen; /* * @fixme, this is very dependent on ordering * * This code should be reworked when we have proper * attribute grouping to coalesce all related index * attributes under a single request OID. */ for (vp = fr_cursor_init(&cursor, &head); vp; vp = fr_cursor_next(&cursor)) { fr_dict_attr_t const *common; /* * We only care about TLV attributes beneath our root */ if (!fr_dict_parent_common(root, vp->da, true)) continue; /* * Sanity checks to ensure we're processing attributes * in the right order. */ common = fr_dict_parent_common(parent, vp->da, true); if (!common) { fr_strerror_printf("Out of order index attributes. \"%s\" is not a child of \"%s\"", vp->da->name, parent->name); return -1; } /* * Index attribute */ if (vp->da->attr == 0) { /* * Print OID from last index/root up to the parent of * the index attribute. */ slen = fr_dict_print_attr_oid(p, end - p, parent, vp->da->parent); if (slen < 0) return -1; if (vp->vp_type != FR_TYPE_UINT32) { fr_strerror_printf("Index attribute \"%s\" is not of type \"integer\"", vp->da->name); return -1; } if (slen >= (end - p)) goto oob; p += slen; /* * Add the value of the index attribute as the next * OID component. */ len = snprintf(p, end - p, ".%i.", vp->vp_uint32); if (is_truncated(len, end - p)) goto oob; p += len; /* * Set the parent to be the attribute representing * the entry. */ parent = fr_dict_attr_child_by_num(vp->da->parent, 1); continue; } /* * Actual TLV attribute */ slen = fr_dict_print_attr_oid(p, end - p, parent, vp->da); if (slen < 0) return -1; /* * Next attribute should be the type */ type_vp = fr_cursor_next(&cursor); if (!type_vp || (type_vp->da != type)) { fr_strerror_printf("No %s found in response, or occurred out of order", type->name); return -1; } type_len = fr_pair_value_snprint(type_buff, sizeof(type_buff), type_vp, '\0'); /* * Build up the vector * * This represents output for a single varbind attribute */ io_vector[0].iov_base = oid_buff; io_vector[0].iov_len = strlen(oid_buff); io_vector[1].iov_base = newline; io_vector[1].iov_len = 1; io_vector[2].iov_base = type_buff; io_vector[2].iov_len = type_len; io_vector[3].iov_base = newline; io_vector[3].iov_len = 1; switch (vp->vp_type) { case FR_TYPE_OCTETS: memcpy(&io_vector[4].iov_base, &vp->vp_strvalue, sizeof(io_vector[4].iov_base)); io_vector[4].iov_len = vp->vp_length; break; case FR_TYPE_STRING: memcpy(&io_vector[4].iov_base, &vp->vp_strvalue, sizeof(io_vector[4].iov_base)); io_vector[4].iov_len = vp->vp_length; break; default: /* * We call fr_value_box_snprint with a NULL da pointer * because we always need return integer values not * value aliases. */ len = fr_value_box_snprint(value_buff, sizeof(value_buff), &vp->data, '\0'); if (is_truncated(len, sizeof(value_buff))) { fr_strerror_printf("Insufficient fixed value buffer"); return -1; } io_vector[4].iov_base = value_buff; io_vector[4].iov_len = len; break; } io_vector[5].iov_base = newline; io_vector[5].iov_len = 1; DEBUG2("said: %s", (char *)io_vector[0].iov_base); DEBUG2("said: %s", (char *)io_vector[2].iov_base); DEBUG2("said: %s", (char *)io_vector[4].iov_base); if (writev(fd, io_vector, sizeof(io_vector) / sizeof(*io_vector)) < 0) { fr_strerror_printf("Failed writing varbind result: %s", fr_syserror(errno)); return -1; } /* * Reset in case we're encoding multiple values */ parent = root; p = oid_buff; type_buff[0] = '\0'; written++; } if (!written && (write(fd, "NONE\n", 5)) < 0) { fr_strerror_printf("Failed writing get response: %s", fr_syserror(errno)); return -1; } return written; }