Esempio n. 1
0
/**
 * 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;
}
Esempio n. 2
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;
}
Esempio n. 3
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;
}
Esempio n. 4
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));
}
Esempio n. 5
0
/**
 * 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;
}
Esempio n. 6
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));
}
Esempio n. 7
0
/**
 * 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;
}
Esempio n. 8
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;
}
Esempio n. 9
0
/**
 * 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;
}
Esempio n. 10
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;
}