Exemplo n.º 1
0
/**
 * Finish a DLEP signal/message
 * @param writer dlep writer
 * @param source logging source for error messages
 * @return -1 if an error happened, 0 otherwise
 */
int
dlep_writer_finish_signal(struct dlep_writer *writer,
    enum oonf_log_source source) {
  size_t length;
  uint16_t tmp16;
  char *dst;

  if (abuf_has_failed(writer->out)) {
    OONF_WARN(source, "Could not build signal: %u",
        writer->signal_type);
    return -1;
  }

  length = abuf_getlen(writer->out) - writer->signal_start;
  if (length > 65535 + 4) {
    OONF_WARN(source, "Signal %u became too long: %" PRINTF_SIZE_T_SPECIFIER,
        writer->signal_type, abuf_getlen(writer->out));
    return -1;
  }

  /* calculate network ordered size */
  tmp16 = htons(length - 4);

  /* put it into the signal */
  dst = abuf_getptr(writer->out);
  memcpy(&dst[writer->signal_start + 2], &tmp16, sizeof(tmp16));

  OONF_DEBUG_HEX(source, &dst[writer->signal_start], length,
      "Finished signal %u:", writer->signal_type);
  return 0;
}
Exemplo n.º 2
0
/**
 * Creates a new raw socket and configures it
 * @param sock empty socket instance
 * @param bind_to address to bind the socket to
 * @param protocol IP protocol number
 * @param recvbuf size of input buffer for socket
 * @param os_if pointer to interface to bind socket on,
 *   NULL if socket should not be bound to an interface
 * @param log_src logging source for error messages
 * @return -1 if an error happened, 0 otherwise
 */
int
os_fd_generic_getrawsocket(struct os_fd *sock,
    const union netaddr_socket *bind_to,
    int protocol, size_t recvbuf, const struct os_interface *os_if,
    enum oonf_log_source log_src __attribute__((unused))) {

  static const int zero = 0;
  int family;

  family = bind_to->std.sa_family;
  sock->fd = socket(family, SOCK_RAW, protocol);
  if (sock->fd < 0) {
    OONF_WARN(log_src, "Cannot open socket: %s (%d)", strerror(errno), errno);
    return -1;
  }

  if (family == AF_INET) {
    if (setsockopt (sock->fd, IPPROTO_IP, IP_HDRINCL, &zero, sizeof(zero)) < 0) {
      OONF_WARN(log_src, "Cannot disable IP_HDRINCL for socket: %s (%d)", strerror(errno), errno);
      os_fd_close(sock);
      return -1;
    }
  }

  if (os_fd_configsocket(sock, bind_to, recvbuf, true, os_if, log_src)) {
    os_fd_close(sock);
    return -1;
  }
  return 0;
}
Exemplo n.º 3
0
/**
 * Write process ID into file
 * @param filename
 * @return -1 if an error happened, 0 otherwise
 */
static int
_write_pidfile(const char *filename) {
  int pid_fd;
  char buffer[16];

  pid_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  if (pid_fd < 0) {
    OONF_WARN(LOG_MAIN, "Could not open pidfile '%s': %s (%d)",
        filename, strerror(errno), errno);
    return -1;
  }

  snprintf(buffer, sizeof(buffer), "%d\n", getpid());

  if (write(pid_fd, buffer, strlen(buffer)+1) < 0) {
    OONF_WARN(LOG_MAIN, "Could not write pid %d into pidfile '%s': %s (%d)",
        getpid(), filename, strerror(errno), errno);
    close(pid_fd);
    return -1;
  }

  close(pid_fd);
  return 0;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
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;
}
Exemplo n.º 6
0
/**
 * Send a data packet through a packet socket. The transmission might not
 * be happen synchronously if the socket would block.
 * @param pktsocket pointer to packet socket
 * @param remote ip/address to send packet to
 * @param data pointer to data to be sent
 * @param length length of data
 * @return -1 if an error happened, 0 otherwise
 */
int
oonf_packet_send(struct oonf_packet_socket *pktsocket, union netaddr_socket *remote,
    const void *data, size_t length) {
  int result;
  struct netaddr_str buf;

  if (abuf_getlen(&pktsocket->out) == 0) {
    /* no backlog of outgoing packets, try to send directly */
    result = os_fd_sendto(&pktsocket->scheduler_entry.fd, data, length, remote,
        pktsocket->config.dont_route);
    if (result > 0) {
      /* successful */
      OONF_DEBUG(LOG_PACKET, "Sent %d bytes to %s %s",
          result, netaddr_socket_to_string(&buf, remote),
          pktsocket->os_if != NULL ? pktsocket->os_if->name : "");
      return 0;
    }

    if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
      OONF_WARN(LOG_PACKET, "Cannot send UDP packet to %s: %s (%d)",
          netaddr_socket_to_string(&buf, remote), strerror(errno), errno);
      return -1;
    }
  }

  /* append destination */
  abuf_memcpy(&pktsocket->out, remote, sizeof(*remote));

  /* append data length */
  abuf_append_uint16(&pktsocket->out, length);

  /* append data */
  abuf_memcpy(&pktsocket->out, data, length);

  /* activate outgoing socket scheduler */
  oonf_socket_set_write(&pktsocket->scheduler_entry, true);
  return 0;
}
Exemplo n.º 7
0
/**
 * Callback to handle data from the olsr socket scheduler
 * @param fd filedescriptor to read data from
 * @param data custom data pointer
 * @param event_read true if read-event is incoming
 * @param event_write true if write-event is incoming
 */
static void
_cb_packet_event(struct oonf_socket_entry *entry,
    bool multicast __attribute__((unused))) {
  struct oonf_packet_socket *pktsocket;
  union netaddr_socket sock;
  uint16_t length;
  char *pkt;
  ssize_t result;
  struct netaddr_str netbuf;

#ifdef OONF_LOG_DEBUG_INFO
  const char *interf = "";
#endif

  pktsocket = container_of(entry, typeof(*pktsocket), scheduler_entry);

#ifdef OONF_LOG_DEBUG_INFO
  if (pktsocket->os_if) {
    interf = pktsocket->os_if->name;
  }
#endif

  if (oonf_socket_is_read(entry)) {
    uint8_t *buf;

    /* clear recvfrom memory */
    memset(&sock, 0, sizeof(sock));

    /* handle incoming data */
    buf = pktsocket->config.input_buffer;

    result = os_fd_recvfrom(&entry->fd,
        buf, pktsocket->config.input_buffer_length-1, &sock,
        pktsocket->os_if);
    if (result > 0 && pktsocket->config.receive_data != NULL) {
      /* handle raw socket */
      if (pktsocket->protocol) {
        buf = os_fd_skip_rawsocket_prefix(buf, &result, pktsocket->local_socket.std.sa_family);
        if (!buf) {
          OONF_WARN(LOG_PACKET, "Error while skipping IP header for socket %s:",
              netaddr_socket_to_string(&netbuf, &pktsocket->local_socket));
          return;
        }
      }
      /* null terminate it */
      buf[result] = 0;

      /* received valid packet */
      OONF_DEBUG(LOG_PACKET, "Received %"PRINTF_SSIZE_T_SPECIFIER" bytes from %s %s (%s)",
          result, netaddr_socket_to_string(&netbuf, &sock),
          interf, multicast ? "multicast" : "unicast");
      pktsocket->config.receive_data(pktsocket, &sock, buf, result);
    }
    else if (result < 0 && (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)) {
      OONF_WARN(LOG_PACKET, "Cannot read packet from socket %s: %s (%d)",
          netaddr_socket_to_string(&netbuf, &pktsocket->local_socket), strerror(errno), errno);
    }
  }

  if (oonf_socket_is_write(entry) && abuf_getlen(&pktsocket->out) > 0) {
    /* handle outgoing data */
    pkt = abuf_getptr(&pktsocket->out);

    /* copy remote socket */
    memcpy(&sock, pkt, sizeof(sock));
    pkt += sizeof(sock);

    /* copy length */
    memcpy(&length, pkt, 2);
    pkt += 2;

    /* try to send packet */
    result = os_fd_sendto(&entry->fd, pkt, length, &sock, pktsocket->config.dont_route);
    if (result < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
      /* try again later */
      OONF_DEBUG(LOG_PACKET, "Sending to %s %s could block, try again later",
          netaddr_socket_to_string(&netbuf, &sock), interf);
      return;
    }

    if (result < 0) {
      /* display error message */
      OONF_WARN(LOG_PACKET, "Cannot send UDP packet to %s: %s (%d)",
          netaddr_socket_to_string(&netbuf, &sock), strerror(errno), errno);
    }
    else {
      OONF_DEBUG(LOG_PACKET, "Sent %"PRINTF_SSIZE_T_SPECIFIER" bytes to %s %s",
          result, netaddr_socket_to_string(&netbuf, &sock), interf);
    }
    /* remove data from outgoing buffer (both for success and for final error */
    abuf_pull(&pktsocket->out, sizeof(sock) + 2 + length);
  }

  if (abuf_getlen(&pktsocket->out) == 0) {
    /* nothing left to send, disable outgoing events */
    oonf_socket_set_write(&pktsocket->scheduler_entry, false);
  }
}
Exemplo n.º 8
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;
}
Exemplo n.º 9
0
/**
 * Callback to receive UDP data through oonf_packet_managed API
 * @param pkt packet socket
 * @param from network socket the packet was received from
 * @param ptr pointer to packet data
 * @param length length of packet data
 */
static void
_cb_receive_udp(struct oonf_packet_socket *pkt,
    union netaddr_socket *from, void *ptr, size_t length) {
  struct dlep_if *interf;
  uint8_t *buffer;
  ssize_t processed;
  struct netaddr_str nbuf;

  interf = pkt->config.user;
  buffer = ptr;

  if (interf->session_tree.count > 0
      && interf->single_session) {
    /* ignore UDP traffic as long as we have a connection */
    return;
  }

  if (length < sizeof(_DLEP_PREFIX) - 1) {
    /* ignore unknown prefix */
    return;
  }

  if (memcmp(buffer, _DLEP_PREFIX, sizeof(_DLEP_PREFIX)-1) != 0) {
    OONF_WARN(interf->session.log_source,
        "Incoming UDP packet with unknown signature");
    return;
  }

  /* advance pointer and fix length */
  buffer += (sizeof(_DLEP_PREFIX) - 1);
  length -= (sizeof(_DLEP_PREFIX) - 1);

  /* copy socket information */
  memcpy(&interf->session.remote_socket, from,
      sizeof(interf->session.remote_socket));

  processed = dlep_session_process_buffer(&interf->session, buffer, length);
  if (processed < 0) {
    return ;
  }

  if ((size_t)processed < length) {
    OONF_WARN(interf->session.log_source,
        "Received malformed or too short UDP packet from %s",
        netaddr_socket_to_string(&nbuf, from));
    /* incomplete or bad packet, just ignore it */
    return;
  }

  if (abuf_getlen(interf->session.writer.out) > sizeof(_DLEP_PREFIX) - 1) {
    /* send an unicast response */
    oonf_packet_send_managed(&interf->udp, from,
        abuf_getptr(interf->session.writer.out),
        abuf_getlen(interf->session.writer.out));
    abuf_clear(interf->session.writer.out);

    /* add dlep prefix to buffer */
    abuf_memcpy(interf->session.writer.out,
        _DLEP_PREFIX, sizeof(_DLEP_PREFIX) - 1);
  }

  netaddr_socket_invalidate(&interf->session.remote_socket);
}
Exemplo n.º 10
0
/**
 * Main program
 * @param argc argument counter
 * @param argv argument vector
 * @param appdata application data
 * @return application return code to shell
 */
int
oonf_main(int argc, char **argv, const struct oonf_appdata *appdata) {
  int return_code;
  int result;

  /* early initialization */
  return_code = 1;

  _schema_name = NULL;
  _display_schema = false;
  _debug_early = false;
  _ignore_unknown = false;

  /* setup signal handler */
  _end_oonf_signal = false;
  setup_signalhandler();

  /* parse "early" command line arguments */
  parse_early_commandline(argc, argv);

  /* initialize core */
  os_core_init(appdata->app_name);

  /* initialize logger */
  if (oonf_log_init(appdata, _debug_early ? LOG_SEVERITY_DEBUG : LOG_SEVERITY_WARN)) {
    goto oonf_cleanup;
  }

  /* prepare plugin initialization */
  oonf_subsystem_init();

  /* initialize configuration system */
  if (oonf_cfg_init(argc, argv, appdata->default_cfg_handler)) {
    goto oonf_cleanup;
  }

  /* add custom configuration definitions */
  oonf_logcfg_init();

  /* parse command line and read configuration files */
  return_code = parse_commandline(argc, argv, appdata, false);
  if (return_code != -1) {
    /* end OONFd now */
    goto oonf_cleanup;
  }

  /* prepare for an error during initialization */
  return_code = 1;

  /* read global section early */
  if ((result = oonf_cfg_update_globalcfg(true))) {
    OONF_WARN(LOG_MAIN, "Cannot read global configuration section (%d)", result);
    goto oonf_cleanup;
  }

  /* configure logger */
  if (oonf_logcfg_apply(oonf_cfg_get_rawdb())) {
    goto oonf_cleanup;
  }

  /* load plugins */
  if (oonf_cfg_load_subsystems()) {
    goto oonf_cleanup;
  }

  /* show schema if necessary */
  if (_display_schema) {
    return_code = display_schema();
    goto oonf_cleanup;
  }

  /* check if we are root, otherwise stop */
  if (appdata->need_root) {
    if (geteuid() != 0) {
      OONF_WARN(LOG_MAIN, "You must be root(uid = 0) to run %s!\n",
          appdata->app_name);
      goto oonf_cleanup;
    }
  }

  if (appdata->need_lock
      && config_global.lockfile != NULL && *config_global.lockfile != 0) {
    /* create application lock */
    if (os_core_create_lockfile(config_global.lockfile)) {
      OONF_WARN(LOG_MAIN, "Could not acquire application lock '%s'",
          config_global.lockfile);
      goto oonf_cleanup;
    }
  }

  /* call initialization callbacks of dynamic plugins */
  oonf_cfg_initplugins();

  /* apply configuration */
  if (oonf_cfg_apply()) {
    goto oonf_cleanup;
  }

  if (!oonf_cfg_is_running()) {
    /*
     * mayor error during late initialization
     * or maybe the user decided otherwise and pressed CTRL-C
     */
    return_code = _end_oonf_signal ? 0 : 1;
    goto oonf_cleanup;
  }

  if (!_handle_scheduling) {
    OONF_WARN(LOG_MAIN, "No event scheduler present");
    return_code = 1;
    goto oonf_cleanup;
  }
  /* see if we need to fork */
  if (config_global.fork && !_display_schema) {
    /* tell main process that we are finished with initialization */
    if (daemon(0,0) < 0) {
      OONF_WARN(LOG_MAIN, "Could not fork into background: %s (%d)",
          strerror(errno), errno);
      goto oonf_cleanup;
    }

    if (config_global.pidfile && *config_global.pidfile != 0) {
      if (_write_pidfile(config_global.pidfile)) {
        goto oonf_cleanup;
      }
    }
  }

  /* activate mainloop */
  return_code = mainloop(argc, argv, appdata);

  /* tell plugins shutdown is in progress */
  oonf_subsystem_initiate_shutdown();

  /* wait for 500 ms and process socket events */
  while(!_handle_scheduling());

oonf_cleanup:
  /* free plugins */
  oonf_cfg_unconfigure_subsystems();
  oonf_subsystem_cleanup();

  /* free logging/config bridge resources */
  oonf_logcfg_cleanup();

  /* free configuration resources */
  oonf_cfg_cleanup();

  /* free logger resources */
  oonf_log_cleanup();

  /* free core resources */
  os_core_cleanup();

  return return_code;
}