/** * Write a DLEP IPv4/IPv6 address/subnet TLV * @param writer dlep writer * @param ip IPv4 address * @param add true if address should be added, false to remove it */ int dlep_writer_add_ip_tlv(struct dlep_writer *writer, const struct netaddr *ip, bool add) { uint8_t value[18]; value[0] = add ? DLEP_IP_ADD : DLEP_IP_REMOVE; netaddr_to_binary(&value[1], ip, 16); switch (netaddr_get_address_family(ip)) { case AF_INET: value[5] = netaddr_get_prefix_length(ip); if (value[5] != 32) { dlep_writer_add_tlv(writer, DLEP_IPV4_SUBNET_TLV, value, 6); } else { dlep_writer_add_tlv(writer, DLEP_IPV4_ADDRESS_TLV, value, 5); } break; case AF_INET6: value[17] = netaddr_get_prefix_length(ip); if (value[17] != 128) { dlep_writer_add_tlv(writer, DLEP_IPV6_SUBNET_TLV, value, 18); } else { dlep_writer_add_tlv(writer, DLEP_IPV6_ADDRESS_TLV, value, 17); } break; default: return -1; } return 0; }
/** * Join a socket into a multicast group * @param sock filedescriptor of socket * @param multicast multicast-group to join * @param os_if pointer to outgoing interface data for multicast * @param log_src logging source for error messages * @return -1 if an error happened, 0 otherwise */ int os_fd_generic_join_mcast_recv(struct os_fd *sock, const struct netaddr *multicast, const struct os_interface *os_if, enum oonf_log_source log_src __attribute__((unused))) { struct netaddr_str buf1, buf2; struct ip_mreq v4_mreq; struct ipv6_mreq v6_mreq; const char *ifname = "*"; if (os_if) { ifname = os_if->name; } if (netaddr_get_address_family(multicast) == AF_INET) { const struct netaddr *src; src = os_if == NULL ? &NETADDR_IPV4_ANY : os_if->if_v4; OONF_DEBUG(log_src, "Socket on interface %s joining receiving multicast %s (src %s)\n", ifname, netaddr_to_string(&buf2, multicast), netaddr_to_string(&buf1, src)); netaddr_to_binary(&v4_mreq.imr_multiaddr, multicast, 4); netaddr_to_binary(&v4_mreq.imr_interface, src, 4); if (setsockopt(sock->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &v4_mreq, sizeof(v4_mreq)) < 0) { OONF_WARN(log_src, "Cannot join multicast group %s (src %s) on interface %s: %s (%d)\n", netaddr_to_string(&buf1, multicast), netaddr_to_string(&buf2, src), ifname, strerror(errno), errno); return -1; } } else { int if_index; if_index = os_if == NULL ? 0 : os_if->index; OONF_DEBUG(log_src, "Socket on interface %s joining receiving multicast %s (if %d)\n", ifname, netaddr_to_string(&buf2, multicast), if_index); netaddr_to_binary(&v6_mreq.ipv6mr_multiaddr, multicast, 16); v6_mreq.ipv6mr_interface = if_index; if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &v6_mreq, sizeof(v6_mreq)) < 0) { OONF_WARN(log_src, "Cannot join multicast group %s on interface %s: %s (%d)\n", netaddr_to_string(&buf1, multicast), ifname, strerror(errno), errno); return -1; } } return 0; }
/** * Join a socket into a multicast group * @param sock filedescriptor of socket * @param multicast multicast ip/port to join * @param os_if pointer to outgoing interface data for multicast * @param loop true if multicast loop should be activated, false otherwise * @param log_src logging source for error messages * @return -1 if an error happened, 0 otherwise */ int os_fd_generic_join_mcast_send(struct os_fd *sock, const struct netaddr *multicast, const struct os_interface *os_if, bool loop, enum oonf_log_source log_src __attribute__((unused))) { struct netaddr_str buf1, buf2; unsigned i; if (netaddr_get_address_family(multicast) == AF_INET) { OONF_DEBUG(log_src, "Socket on interface %s joining sending multicast %s (src %s)\n", os_if->name, netaddr_to_string(&buf2, multicast), netaddr_to_string(&buf1, os_if->if_v4)); if (setsockopt(sock->fd, IPPROTO_IP, IP_MULTICAST_IF, netaddr_get_binptr(os_if->if_v4), 4) < 0) { OONF_WARN(log_src, "Cannot set multicast %s on interface %s (src %s): %s (%d)\n", netaddr_to_string(&buf2, multicast), os_if->name, netaddr_to_string(&buf1, os_if->if_v4), strerror(errno), errno); return -1; } i = loop ? 1 : 0; if(setsockopt(sock->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&i, sizeof(i)) < 0) { OONF_WARN(log_src, "Cannot %sactivate local loop of multicast interface: %s (%d)\n", loop ? "" : "de", strerror(errno), errno); return -1; } } else { OONF_DEBUG(log_src, "Socket on interface %s (%d) joining sending multicast %s (src %s)\n", os_if->name, os_if->index, netaddr_to_string(&buf2, multicast), netaddr_to_string(&buf1, os_if->if_linklocal_v6)); if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &os_if->index, sizeof(os_if->index)) < 0) { OONF_WARN(log_src, "Cannot set multicast %s on interface %s (src %s): %s (%d)\n", netaddr_to_string(&buf2, multicast), os_if->name, netaddr_to_string(&buf1, os_if->if_linklocal_v6), strerror(errno), errno); return -1; } i = loop ? 1 : 0; if(setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &i, sizeof(i)) < 0) { OONF_WARN(log_src, "Cannot deactivate local loop of multicast interface: %s (%d)\n", strerror(errno), errno); return -1; } } return 0; }
/** * Write a DLEP IPv6 address TLV * @param writer dlep writer * @param ipv6 IPv6 address * @param add true if address should be added, false to remove it */ void dlep_writer_add_ipv6_tlv(struct dlep_writer *writer, const struct netaddr *ipv6, bool add) { uint8_t value[17]; if (netaddr_get_address_family(ipv6) != AF_INET6) { return; } value[0] = add ? DLEP_IP_ADD : DLEP_IP_REMOVE; netaddr_to_binary(&value[1], ipv6, 16); dlep_writer_add_tlv(writer, DLEP_IPV6_ADDRESS_TLV, value, sizeof(value)); }
/** * Write a DLEP MAC address TLV * @param writer dlep writer * @param mac_lid mac address/LID * @return -1 if address was wrong type, 0 otherwise */ int dlep_writer_add_mac_tlv(struct dlep_writer *writer, const struct oonf_layer2_neigh_key *mac_lid) { uint8_t value[8]; switch (netaddr_get_address_family(&mac_lid->addr)) { case AF_MAC48: case AF_EUI64: break; default: return -1; } netaddr_to_binary(value, &mac_lid->addr, 8); dlep_writer_add_tlv(writer, DLEP_MAC_ADDRESS_TLV, value, netaddr_get_binlength(&mac_lid->addr)); return 0; }
/** * Write a DLEP IPv6 conpoint TLV * @param writer dlep writer * @param addr IPv6 address * @param port port number * @param tls TLS capability flag */ void dlep_writer_add_ipv6_conpoint_tlv(struct dlep_writer *writer, const struct netaddr *addr, uint16_t port, bool tls) { uint8_t value[19]; if (netaddr_get_address_family(addr) != AF_INET6) { return; } /* convert port to network byte order */ port = htons(port); /* copy data into value buffer */ value[0] = tls ? DLEP_CONNECTION_TLS : DLEP_CONNECTION_PLAIN; netaddr_to_binary(&value[1], addr, sizeof(value)); memcpy(&value[17], &port, sizeof(port)); dlep_writer_add_tlv(writer, DLEP_IPV6_CONPOINT_TLV, &value, sizeof(value)); }
/** * Write a DLEP MAC address TLV * @param writer dlep writer * @param mac mac address * @return -1 if address was wrong type, 0 otherwise */ int dlep_writer_add_mac_tlv(struct dlep_writer *writer, const struct netaddr *mac) { uint8_t value[8]; switch (netaddr_get_address_family(mac)) { case AF_MAC48: case AF_EUI64: break; default: return -1; } netaddr_to_binary(value, mac, 8); dlep_writer_add_tlv(writer, DLEP_MAC_ADDRESS_TLV, value, netaddr_get_binlength(mac)); return 0; }
/** * Validate if a value against a specific network address * @param out output buffer for error messages * @param section_name name of configuration section * @param entry_name name of configuration entry * @param value value that needs to be validated * @param prefix true if the address might be a network prefix * @param af_types list of address families the address might be * @param af_types_count number of address families specified * @return 0 if value is valid, -1 otherwise */ int cfg_validate_netaddr(struct autobuf *out, const char *section_name, const char *entry_name, const char *value, bool prefix, const int8_t *af_types, size_t af_types_count) { struct netaddr addr; uint8_t max_prefix; size_t i; if (netaddr_from_string(&addr, value)) { cfg_append_printable_line(out, "Value '%s' for entry '%s'" " in section %s is no valid network address", value, entry_name, section_name); return -1; } max_prefix = netaddr_get_maxprefix(&addr); /* check prefix length */ if (netaddr_get_prefix_length(&addr) > max_prefix) { cfg_append_printable_line(out, "Value '%s' for entry '%s'" " in section %s has an illegal prefix length", value, entry_name, section_name); return -1; } if (!prefix && netaddr_get_prefix_length(&addr) != max_prefix) { cfg_append_printable_line(out, "Value '%s' for entry '%s'" " in section %s must be a single address, not a prefix", value, entry_name, section_name); return -1; } for (i=0; i<af_types_count; i++) { if (af_types[i] == netaddr_get_address_family(&addr)) { return 0; } } /* at least one condition was set, but no one matched */ cfg_append_printable_line(out, "Value '%s' for entry '%s'" " in section '%s' is wrong address type", value, entry_name, section_name); return -1; }
/** * Apply new configuration to a managed stream socket * @param managed pointer to managed stream * @param stream pointer to TCP stream to configure * @param bindto local address to bind socket to * set to AF_UNSPEC for simple reinitialization * @param port local port number * @param dscp dscp value for outgoing traffic * @param protocol IP protocol for raw IP socket, 0 otherwise * @param data interface data to bind socket to, might be NULL * @return -1 if an error happened, 0 if everything is okay, * 1 if the socket wasn't touched. */ static int _apply_managed_socket(struct oonf_packet_managed *managed, struct oonf_packet_socket *packet, const struct netaddr *bindto, int port, uint8_t dscp, int protocol, struct os_interface *data) { union netaddr_socket sock; struct netaddr_str buf; /* create binding socket */ if (netaddr_socket_init(&sock, bindto, port, data == NULL ? 0 : data->index)) { OONF_WARN(LOG_PACKET, "Cannot create managed socket address: %s/%u", netaddr_to_string(&buf, bindto), port); return -1; } if (list_is_node_added(&packet->node)) { if (data == packet->os_if && memcmp(&sock, &packet->local_socket, sizeof(sock)) == 0 && protocol == packet->protocol) { /* nothing changed */ return 1; } } else { if (data != NULL && !data->flags.up) { /* nothing changed */ return 1; } } /* remove old socket */ oonf_packet_remove(packet, true); if (data != NULL && !data->flags.up) { OONF_DEBUG(LOG_PACKET, "Interface %s of socket is down", data->name); return 0; } /* copy configuration */ memcpy(&packet->config, &managed->config, sizeof(packet->config)); if (packet->config.user == NULL) { packet->config.user = managed; } /* create new socket */ if (protocol) { if (oonf_packet_raw_add(packet, protocol, &sock, data)) { return -1; } } else { if (oonf_packet_add(packet, &sock, data)) { return -1; } } if (os_fd_set_dscp(&packet->scheduler_entry.fd, dscp, netaddr_get_address_family(bindto) == AF_INET6)) { OONF_WARN(LOG_PACKET, "Could not set DSCP value for socket: %s (%d)", strerror(errno), errno); oonf_packet_remove(packet, true); return -1; } packet->os_if = data; OONF_DEBUG(LOG_PACKET, "Opened new socket and bound it to %s (if %s)", netaddr_to_string(&buf, bindto), data != NULL ? data->name : "any"); return 0; }
/** * Apply a new configuration to an unicast/multicast socket pair * @param managed pointer to managed socket * @param data pointer to interface to bind sockets, NULL if unbound socket * @param sock pointer to unicast packet socket * @param bind_ip address to bind unicast socket to * @param mc_sock pointer to multicast packet socket * @param mc_ip multicast address * @return */ static int _apply_managed_socketpair(int af_type, struct oonf_packet_managed *managed, struct os_interface *os_if, bool *changed, struct oonf_packet_socket *sock, struct oonf_packet_socket *mc_sock, struct netaddr *mc_ip) { struct netaddr_acl *bind_ip_acl; int sockstate = 0, result = 0; uint16_t mc_port; bool real_multicast; const struct netaddr *bind_ip; bind_ip_acl = &managed->_managed_config.bindto; /* copy unicast port if necessary */ mc_port = managed->_managed_config.multicast_port; if (mc_port == 0) { mc_port = managed->_managed_config.port; } /* Get address the unicast socket should bind on */ if (os_if != NULL && !os_if->flags.up) { bind_ip = NULL; } else if (os_if != NULL && netaddr_get_address_family(os_if->if_linklocal_v6) == af_type && netaddr_acl_check_accept(bind_ip_acl, os_if->if_linklocal_v6)) { bind_ip = os_if->if_linklocal_v6; } else if (os_if != NULL && netaddr_get_address_family(os_if->if_linklocal_v4) == af_type && netaddr_acl_check_accept(bind_ip_acl, os_if->if_linklocal_v4)) { bind_ip = os_if->if_linklocal_v4; } else { bind_ip = os_interface_get_bindaddress(af_type, bind_ip_acl, os_if); } if (!bind_ip) { oonf_packet_remove(sock, false); oonf_packet_remove(mc_sock, false); return 0; } /* handle loopback interface */ if (os_if != NULL && os_if->flags.loopback && netaddr_get_address_family(mc_ip) != AF_UNSPEC) { memcpy(mc_ip, bind_ip, sizeof(*mc_ip)); } /* check if multicast IP is a real multicast (and not a broadcast) */ real_multicast = netaddr_is_in_subnet( netaddr_get_address_family(mc_ip) == AF_INET ? &NETADDR_IPV4_MULTICAST : &NETADDR_IPV6_MULTICAST, mc_ip); sockstate = _apply_managed_socket( managed, sock, bind_ip, managed->_managed_config.port, managed->_managed_config.dscp, managed->_managed_config.rawip ? managed->_managed_config.protocol : 0, os_if); if (sockstate == 0) { /* settings really changed */ *changed = true; if (real_multicast && os_if != NULL && os_if->flags.up) { os_fd_join_mcast_send(&sock->scheduler_entry.fd, mc_ip, os_if, managed->_managed_config.loop_multicast, LOG_PACKET); } } else if (sockstate < 0) { /* error */ result = -1; oonf_packet_remove(sock, true); } if (real_multicast && netaddr_get_address_family(mc_ip) != AF_UNSPEC) { /* multicast */ sockstate = _apply_managed_socket( managed, mc_sock, mc_ip, mc_port, managed->_managed_config.dscp, managed->_managed_config.rawip ? managed->_managed_config.protocol : 0, os_if); if (sockstate == 0) { /* settings really changed */ *changed = true; mc_sock->scheduler_entry.process = _cb_packet_event_multicast; /* join multicast group */ os_fd_join_mcast_recv(&mc_sock->scheduler_entry.fd, mc_ip, os_if, LOG_PACKET); } else if (sockstate < 0) { /* error */ result = -1; oonf_packet_remove(sock, true); } } else { oonf_packet_remove(mc_sock, true); /* * initialize anyways because we use it for sending broadcasts with * oonf_packet_send_managed_multicast() */ netaddr_socket_init(&mc_sock->local_socket, mc_ip, mc_port, os_if == NULL ? 0 : os_if->index); } return result; }