Ejemplo n.º 1
0
int main(int argc, char **argv)
{
  int err, publish;
  hip_hit hit;
  struct sockaddr_storage addr;
  struct sockaddr_in *addr4 = (struct sockaddr_in*)&addr;

  /*
   * Load hip.conf configuration file
   * user may have provided path using command line, or search defaults
   */
  memset(HCNF, 0, sizeof(HCNF));
  if ((locate_config_file(HCNF.conf_filename, sizeof(HCNF.conf_filename),
                          HIP_CONF_FILENAME) < 0) ||
      (read_conf_file(HCNF.conf_filename) < 0))
    {
      log_(ERR, "Problem with configuration file, using defaults.\n");
    }
  else
    {
      log_(NORM, "Using configuration file:\t%s\n",
           HCNF.conf_filename);
    }


  memset(&addr, 0, sizeof(addr));
  addr4->sin_family = AF_INET;
  addr4->sin_addr.s_addr = inet_addr("192.168.1.2");
  hex_to_bin("7BE901B3AF2679C8C580619535641713", hit, HIT_SIZE);

  printf("Doing XML RPC put 1...\n");
  err = hip_dht_publish(&hit, (struct sockaddr*)&addr);
  printf("return value = %d\n", err);

  addr4->sin_addr.s_addr = inet_addr("192.168.2.7");

  printf("Doing XML RPC put 2...\n");
  err = hip_dht_publish(&hit, (struct sockaddr*)&addr);
  printf("return value = %d\n", err);

  memset(&addr, 0, sizeof(addr));
  addr4->sin_family = AF_INET;

  printf("addr is at: %p\n", &addr);
  printf("Doing XML RPC get...\n");
  err = hip_dht_lookup_address(&hit, (struct sockaddr*)&addr);
  printf("return value = %d\n", err);
  printf("Address = %s\n", logaddr((struct sockaddr*)&addr));
  return(0);
}
Ejemplo n.º 2
0
int std_subscribe(const char *dir,
		  const char *subdir,
		  const char *userhost,
		  int flagadd,
		  const char *comment,
		  const char *event,
		  int forcehash)
/* add (flagadd=1) or remove (flagadd=0) userhost from the subscr. database  */
/* dbname. Comment is e.g. the subscriber from line or name. It is added to  */
/* the log. Event is the action type, e.g. "probe", "manual", etc. The       */
/* direction (sub/unsub) is inferred from flagadd. Returns 1 on success, 0   */
/* on failure. If flagmysql is set and the file "sql" is found in the        */
/* directory dbname, it is parsed and a mysql db is assumed. if forcehash is */
/* >=0 it is used in place of the calculated hash. This makes it possible to */
/* add addresses with a hash that does not exist. forcehash has to be 0..99. */
/* for unsubscribes, the address is only removed if forcehash matches the    */
/* actual hash. This way, ezmlm-manage can be prevented from touching certain*/
/* addresses that can only be removed by ezmlm-unsub. Usually, this would be */
/* used for sublist addresses (to avoid removal) and sublist aliases (to     */
/* prevent users from subscribing them (although the cookie mechanism would  */
/* prevent the resulting duplicate message from being distributed. */
{
  int fdlock;

  unsigned int j;
  unsigned char ch,lcch;
  int match;
  int flagwasthere;

  if (userhost[str_chr(userhost,'\n')])
    strerr_die2x(100,FATAL,ERR_ADDR_NL);

    if (!stralloc_copys(&addr,"T")) die_nomem();
    if (!stralloc_cats(&addr,userhost)) die_nomem();
    if (addr.len > 401)
      strerr_die2x(100,FATAL,ERR_ADDR_LONG);

    j = byte_rchr(addr.s,addr.len,'@');
    if (j == addr.len)
      strerr_die2x(100,FATAL,ERR_ADDR_AT);
    case_lowerb(addr.s + j + 1,addr.len - j - 1);
    if (!stralloc_copy(&lcaddr,&addr)) die_nomem();
    case_lowerb(lcaddr.s + 1,j - 1);	/* make all-lc version of address */

    if (forcehash >= 0 && forcehash <= 52) {
      ch = lcch = 64 + (unsigned char) forcehash;
    } else {
      ch = 64 + subhashsa(&addr);
      lcch = 64 + subhashsa(&lcaddr);
    }

    if (!stralloc_0(&addr)) die_nomem();
    if (!stralloc_0(&lcaddr)) die_nomem();
    std_makepath(&fn,dir,subdir,"/subscribers/",lcch);
    std_makepath(&fnlock,dir,subdir,"/lock",0);

    if (!stralloc_copyb(&fnnew,fn.s,fn.len-1)) die_nomem();
	/* code later depends on fnnew = fn + 'n' */
    if (!stralloc_cats(&fnnew,"n")) die_nomem();
    if (!stralloc_0(&fnnew)) die_nomem();

    fdlock = lockfile(fnlock.s);

				/* do lower case hashed version first */
    fdnew = open_trunc(fnnew.s);
    if (fdnew == -1) die_write();
    substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));

    flagwasthere = 0;

    fd = open_read(fn.s);
    if (fd == -1) {
      if (errno != error_noent) { close(fdnew); die_read(); }
    }
    else {
      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));

      for (;;) {
        if (getln(&ss,&line,&match,'\0') == -1) {
	  close(fd); close(fdnew); die_read();
        }
        if (!match) break;
        if (line.len == addr.len)
          if (!case_diffb(line.s,line.len,addr.s)) {
	    flagwasthere = 1;
	    if (!flagadd)
	      continue;
	  }
        if (substdio_bput(&ssnew,line.s,line.len) == -1) {
	  close(fd); close(fdnew); die_write();
        }
      }

      close(fd);
    }

    if (flagadd && !flagwasthere)
      if (substdio_bput(&ssnew,addr.s,addr.len) == -1) {
        close(fdnew); die_write();
      }

    if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(); }
    if (fsync(fdnew) == -1) { close(fdnew); die_write(); }
    close(fdnew);

    if (rename(fnnew.s,fn.s) == -1)
      strerr_die6sys(111,FATAL,ERR_MOVE,fnnew.s," to ",fn.s,": ");

    if ((ch == lcch) || flagwasthere) {
      close(fdlock);
      if (flagadd ^ flagwasthere) {
        if (!stralloc_0(&addr)) die_nomem();
        logaddr(dir,subdir,event,addr.s+1,comment);
        return 1;
      }
      return 0;
    }

			/* If unsub and not found and hashed differ, OR */
			/* sub and not found (so added with new hash) */
			/* do the 'case-dependent' hash */

    fn.s[fn.len - 2] = ch;
    fnnew.s[fnnew.len - 3] = ch;
    fdnew = open_trunc(fnnew.s);
    if (fdnew == -1) die_write();
    substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));

    fd = open_read(fn.s);
    if (fd == -1) {
      if (errno != error_noent) { close(fdnew); die_read(); }
    } else {
      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));

      for (;;) {
        if (getln(&ss,&line,&match,'\0') == -1)
          { close(fd); close(fdnew); die_read(); }
        if (!match) break;
        if (line.len == addr.len)
          if (!case_diffb(line.s,line.len,addr.s)) {
            flagwasthere = 1;
            continue;	/* always want to remove from case-sensitive hash */
          }
        if (substdio_bput(&ssnew,line.s,line.len) == -1)
          { close(fd); close(fdnew); die_write(); }
      }

      close(fd);
    }

    if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(); }
    if (fsync(fdnew) == -1) { close(fdnew); die_write(); }
    close(fdnew);

    if (rename(fnnew.s,fn.s) == -1)
      strerr_die6sys(111,FATAL,ERR_MOVE,fnnew.s," to ",fn.s,": ");

    close(fdlock);
    if (flagadd ^ flagwasthere) {
      if (!stralloc_0(&addr)) die_nomem();
      logaddr(dir,subdir,event,addr.s+1,comment);
      return 1;
    }
    return 0;

}
Ejemplo n.º 3
0
/*
 * \fn hip_xmlrpc_getput()
 *
 * \param mode		determines get or put, app, retry on/off
 *		         If retry is off only one attempt should be made,
 *                       on means the connect() should keep retrying
 * \param app		string to use in the XML RPC application field
 * \param server	server address and port to connect to
 * \param key           DHT key used for get or put
 * \param key_len	length of DHT key in bytes
 * \param value		DHT value used for put, ptr for storing value for get
 * \param value_len	ptr to length of value buffer, length of get is returned
 * \param secret	secret value used to make put removable
 * \param secret_len	length of secret value
 * \param ttl		time to live in seconds
 *
 * \brief Perform the XML RPC GET, PUT, and RM operations.
 */
int hip_xmlrpc_getput(int mode, char *app, struct sockaddr *server,
                      char *key, int key_len, char *value, int *value_len,
                      char *secret, int secret_len, int ttl)
{
  xmlDocPtr doc = NULL;
  xmlNodePtr root_node = NULL, node;
  int len = 0, s, retval = 0;
  char buff[2048], oper[14];
  unsigned char key64[2 * DHT_KEY_SIZE], val64[2 * DHT_VAL_SIZE];
  unsigned char tmp[2 * DHT_VAL_SIZE], *xmlbuff = NULL;
  fd_set read_fdset;
  struct timeval timeout, now;
  char *p;
  unsigned int retry_attempts = 0;
  struct sockaddr_in src_addr;
  struct dht_val *dv, rm;
  SHA_CTX c;
  __u8 secret_hash[SHA_DIGEST_LENGTH], value_hash[SHA_DIGEST_LENGTH];
  int rm_ttl = 0, value_hash_len;

  int retry = ((mode & 0x00F0) == XMLRPC_MODE_RETRY_ON);

  if ((key_len > (2 * DHT_KEY_SIZE)) ||
      (*value_len > (2 * DHT_VAL_SIZE)))
    {
      return(-1);
    }

  /*
   * support for removable puts
   */
  memset(&rm, 0, sizeof(struct dht_val));
  if ((mode & 0x000F) == XMLRPC_MODE_PUT)
    {
      /*
       * produce hashes of the secret and the value, for later removal
       */
      SHA1_Init(&c);
      SHA1_Update(&c, value, *value_len);
      SHA1_Final(value_hash, &c);
      SHA1_Init(&c);
      SHA1_Update(&c, secret, secret_len);
      SHA1_Final(secret_hash, &c);

      /*
       * check if we already published a record with this key; record
       * this new secret value and value_hash
       */
      pthread_mutex_lock(&dht_vals_lock);
      gettimeofday(&now, NULL);
      dv = lookup_dht_val(key);
      if (dv)
        {
          /* save old secret so we can remove it later below */
          memcpy(&rm, &dv, sizeof(struct dht_val));
          /* any time left for removing the old record? */
          rm_ttl = TDIFF(rm.expire_time, now);
        }
      else
        {
          dv = insert_dht_val(key);
        }
      strncpy(dv->app, app, sizeof(dv->app));
      dv->value_hash_len = SHA_DIGEST_LENGTH;
      memcpy(dv->value_hash, value_hash, SHA_DIGEST_LENGTH);
      dv->secret_len = secret_len;
      memcpy(dv->secret, secret, secret_len);
      dv->expire_time.tv_usec = now.tv_usec;
      dv->expire_time.tv_sec = now.tv_sec + ttl;
      pthread_mutex_unlock(&dht_vals_lock);
    }

  switch (mode & 0x000F)
    {
    case XMLRPC_MODE_PUT:
      sprintf(oper, "put_removable");
      break;
    case XMLRPC_MODE_GET:
      sprintf(oper, "get");
      break;
    case XMLRPC_MODE_RM:
      sprintf(oper, "rm");
      break;
    default:
      log_(WARN, "Invalid XMLRPC mode given to DHT.\n");
      return(-1);
    }

  /*
   * create a new XML document
   */
  doc = xmlNewDoc(BAD_CAST "1.0");
  root_node = xmlNewNode(NULL, BAD_CAST "methodCall");
  xmlDocSetRootElement(doc, root_node);
  node = xmlNewChild(root_node, NULL, BAD_CAST "methodName",
                     BAD_CAST oper);
  node = xmlNewChild(root_node, NULL, BAD_CAST "params", NULL);
  memset(tmp, 0, sizeof(tmp));
  memcpy(tmp, key, key_len);
  EVP_EncodeBlock(key64, tmp, key_len);
  xml_new_param(node, "base64", (char *)key64);                 /* key */
  /* log_(NORM, "Doing %s using key(%d)=",
   *    ((mode & 0x000F)==XMLRPC_MODE_PUT) ? "PUT":"GET", key_len);
   *  print_hex(key, key_len);
   *  log_(NORM, " [%s]\n", key64); // */
  switch (mode & 0x000F)
    {
    case XMLRPC_MODE_PUT:
      memset(tmp, 0, sizeof(tmp));
      memcpy(tmp, value, *value_len);
      EVP_EncodeBlock(val64, tmp, *value_len);
      xml_new_param(node, "base64", (char *)val64);             /* value */
      xml_new_param(node, "string", "SHA");                     /* hash type */
      memset(tmp, 0, sizeof(tmp));
      memcpy(tmp, secret_hash, SHA_DIGEST_LENGTH);
      EVP_EncodeBlock(val64, tmp, SHA_DIGEST_LENGTH);
      xml_new_param(node, "base64", (char *)val64);            /* secret_hash */
      sprintf((char *)tmp, "%d", ttl);
      xml_new_param(node, "int", (char *)tmp);                  /* lifetime */
      break;
    case XMLRPC_MODE_GET:
      xml_new_param(node, "int", "10");                 /* maxvals */
      xml_new_param(node, "base64", "");                /* placemark */
      memset(value, 0, *value_len);
      break;
    case XMLRPC_MODE_RM:
      memset(tmp, 0, sizeof(tmp));
      memcpy(tmp, value_hash, SHA_DIGEST_LENGTH);
      EVP_EncodeBlock(val64, tmp, SHA_DIGEST_LENGTH);
      xml_new_param(node, "base64", (char *)val64);             /* value_hash */
      xml_new_param(node, "string", "SHA");                     /* hash type */
      memset(tmp, 0, sizeof(tmp));
      memcpy(tmp, secret, secret_len);
      EVP_EncodeBlock(val64, tmp, secret_len);
      xml_new_param(node, "base64", (char *)val64);             /* secret */
      sprintf((char *)tmp, "%d", ttl);
      xml_new_param(node, "int", (char *)tmp);                  /* lifetime */
    }
  xml_new_param(node, "string", app);                   /* app */
  xmlDocDumpFormatMemory(doc, &xmlbuff, &len, 0);

  /*
   * Build an HTTP POST and transmit to server
   */
  memset(buff, 0, sizeof(buff));
  build_http_post_header(buff, len, server);       /* len is XML length above */
  memcpy(&buff[strlen(buff)], xmlbuff, len);
  xmlFree(xmlbuff);
  len = strlen(buff) + 1;
connect_retry:
  /* Connect and send the XML RPC */
  if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    {
      log_(WARN, "DHT connect - socket error: %s\n", strerror(errno));
      retval = -1;
      goto putget_exit;
    }
  /* Use the preferred address as source */
  memset(&src_addr, 0, sizeof(src_addr));
  src_addr.sin_family = AF_INET;
  src_addr.sin_addr.s_addr = get_preferred_addr();
  if (!src_addr.sin_addr.s_addr)
    {
      log_(NORM, "No preferred address, deferring DHT!\n");
      return(-1);
    }
  log_(NORM, "Using source address of %s for DHT %s.\n",
       logaddr(SA(&src_addr)), oper);
  fflush(stdout);
  if (bind(s, SA(&src_addr), SALEN(&src_addr)) < 0)
    {
      log_(WARN, "DHT connect - bind error: %s\n", strerror(errno));
    }

  if (g_state != 0)
    {
      return(-1);
    }
  if (retry && (retry_attempts > 0))
    {
      /* quit after a certain number of retries */
      if (retry_attempts >= HCNF.max_retries)
        {
          retval = -2;
          goto putget_exit;
        }
      /* wait packet_timeout seconds before retrying */
      hip_sleep(HCNF.packet_timeout);
    }
  retry_attempts++;

  if (connect(s, server, SALEN(server)) < 0)
    {
      log_(WARN, "DHT server connect error: %s\n", strerror(errno));
      closesocket(s);
#ifdef __WIN32__
      errno = WSAGetLastError();
      if (retry && ((errno == WSAETIMEDOUT) ||
                    (errno == WSAENETUNREACH)))
        {
          goto connect_retry;
        }
#else
      if (retry &&
          ((errno == ETIMEDOUT) || (errno == EHOSTUNREACH)))
        {
          goto connect_retry;
        }
#endif
      retval = -3;
      goto putget_exit;
    }

  if (send(s, buff, len, 0) != len)
    {
      log_(WARN, "DHT sent incorrect number of bytes\n");
      retval = -4;
      goto putget_exit;
    }
  xmlFreeDoc(doc);
  doc = NULL;

  /*
   * Receive XML RPC response from server
   */
  FD_ZERO(&read_fdset);
  FD_SET((unsigned int)s, &read_fdset);
  /* use longer timeout when retry==TRUE, because we have own thread */
  if (retry)
    {
      timeout.tv_sec = 3;
      timeout.tv_usec = 0;
    }
  else
    {
      timeout.tv_sec = 0;
      timeout.tv_usec = 300000;           /* 300ms */
    }
  if (select(s + 1, &read_fdset, NULL, NULL, &timeout) < 0)
    {
      log_(WARN, "DHT select error: %s\n", strerror(errno));
      retval = -5;
      goto putget_exit;
    }
  else if (FD_ISSET(s, &read_fdset))
    {
      if ((len = recv(s, buff, sizeof(buff) - 1, 0)) <= 0)
        {
          log_(WARN, "DHT error receiving from server: %s\n",
               strerror(errno));
          retval = -6;
          goto putget_exit;
        }
      if (strncmp(buff, "HTTP", 4) != 0)
        {
          return(-7);
        }
      if ((p = strstr(buff, "Content-Length: ")) == NULL)
        {
          return(-8);
        }
      else               /* advance ptr to Content-Length */
        {
          p += 16;
        }
      sscanf(p, "%d", &len);
      p = strchr(p, '\n') + 3;           /* advance to end of line */
      retval = hip_xmlrpc_parse_response(mode, p, len,
                                         value, value_len);
      log_(NORM, "DHT server responded with return code %d (%s).\n",
           retval, hip_xmlrpc_resp_to_str(retval));
    }
  else
    {
      /* select timeout */
      if (retry)             /* XXX testme: retry select instead? */
        {
          goto connect_retry;
        }
      retval = -9;
    }

putget_exit:
#ifdef __WIN32__
  closesocket(s);
#else
  close(s);
#endif
  if (doc != NULL)
    {
      xmlFreeDoc(doc);
    }
  if (rm_ttl > 0)
    {
      value_hash_len = sizeof(rm.value_hash);
      hip_xmlrpc_getput(((mode & 0x00F0) | XMLRPC_MODE_RM),
                        app, server, key, key_len,
                        (char *)rm.value_hash, &value_hash_len,
                        (char *)rm.secret, secret_len, rm_ttl);
    }
  return(retval);
}
Ejemplo n.º 4
0
/*
 * \fn hip_dht_lookup_address()
 *
 * \param hit		pointer to HIT for use with the lookup
 * \param addr		pointer to sockaddr_storage for storing the returned
 *                      LOCATOR
 * \param retry		if TRUE we will retry failed connection attempts
 *
 * \return              Returns 0 on success, -1 on error.
 *
 * \brief Given a HIT, lookup an address using a DHT server.
 */
int hip_dht_lookup_address(hip_hit *hit, struct sockaddr *addr, int retry)
{
  int mode, err, value_len;
  struct sockaddr_storage ss_server;
  struct sockaddr *server = (struct sockaddr*)&ss_server;
  __u8 dht_key[DHT_KEY_SIZE], hdrr[DHT_VAL_SIZE], *p_addr;
  int location, type, length, len, data_len, sig_verified = FALSE;
  hiphdr *hiph;
  tlv_head *tlv;
  locator *loc;
  hi_node *peer_hi = NULL;

  if (hip_dht_select_server(server) < 0)
    {
      return(-1);
    }

  /*
   * Prepare the DHT key: HIT_KEY (100 middle bits of HIT + padding)
   */
  hit2hit_key(hit, dht_key);

  /*
   * For the Bamboo DHT (OpenDHT), this is tied
   * to an XML RPC "GET" call
   */
  memset(hdrr, 0, DHT_VAL_SIZE);
  value_len = DHT_VAL_SIZE;
  mode = XMLRPC_MODE_GET;
  mode |= (retry) ? XMLRPC_MODE_RETRY_ON : XMLRPC_MODE_RETRY_OFF;
  err = hip_xmlrpc_getput(mode,
                          XMLRPC_APP_ADDR,
                          server,
                          (char *)dht_key,
                          DHT_KEY_SIZE,
                          (char *)hdrr,
                          &value_len,
                          NULL,
                          0,
                          0);
  if (err < 0)
    {
      return(err);
    }
  if (parse_hdrr(hdrr, value_len) < 0)
    {
      return(-1);
    }

  /*
   * Validate the signature and grab the LOCATOR that matches
   * the address family provided in addr.
   */
  location = 0;
  hiph = (hiphdr*) &hdrr[location];
  data_len = location + ((hiph->hdr_len + 1) * 8);
  location += sizeof(hiphdr);
  while (location < data_len)
    {
      tlv = (tlv_head*) &hdrr[location];
      type = ntohs(tlv->type);
      length = ntohs(tlv->length);
      /* first verify SIGNATURE */
      if (!sig_verified && peer_hi &&
          (type == PARAM_HIP_SIGNATURE))
        {
          len = eight_byte_align(location);
          hiph->checksum = 0;
          hiph->hdr_len = (len / 8) - 1;
          if (validate_signature(hdrr, len, tlv,
                                 peer_hi->dsa,
                                 peer_hi->rsa) < 0)
            {
              log_(WARN, "HDRR has invalid signature.\n");
              err = -1;
              break;
            }
          else
            {
              log_(NORM, "Signature in HDRR validated OK.\n");
            }
          sig_verified = TRUE;
          location = sizeof(hiphdr);
          continue;
        }
      else if (!sig_verified && (type == PARAM_HOST_ID))
        {
          if (handle_hi(&peer_hi, &hdrr[location]) < 0)
            {
              log_(WARN, "Error with HI from HDRR.\n");
              err = -1;
              break;
            }
          if (!validate_hit(hiph->hit_sndr, peer_hi))
            {
              log_(WARN, "HI in HDRR does not match the "
                   "sender's HIT\n");
              err = -1;
              break;
            }
          else
            {
              log_(NORM, "HI in HDRR validates the sender's "
                   "HIT.\n");
            }
        }
      if (type == PARAM_LOCATOR)
        {
          loc = ((tlv_locator*)tlv)->locator1;
          if ((loc->locator_type == LOCATOR_TYPE_IPV6) &&
              (loc->locator_length == 4))
            {
              p_addr = &loc->locator[0];
            }
          else if ((loc->locator_type == LOCATOR_TYPE_SPI_IPV6)
                   && (loc->locator_length == 5))
            {
              p_addr = &loc->locator[4];
            }
          else
            {
              log_(WARN, "HDRR has unknown LOCATOR type.\n");
              err = -1;
              break;
            }
          if (IN6_IS_ADDR_V4MAPPED(
                (struct in6_addr*)p_addr))
            {
              addr->sa_family = AF_INET;
              memcpy(SA2IP(addr), p_addr + 12, SAIPLEN(addr));
              if (IN_MULTICAST(*(SA2IP(addr))))
                {
                  err = -1;
                  break;
                }
              if (((struct sockaddr_in*)addr)->sin_addr.
                  s_addr
                  == INADDR_BROADCAST)
                {
                  err = -1;
                  break;
                }
            }
          else
            {
              unsigned char *p = SA2IP(addr);
              addr->sa_family = AF_INET6;
              memcpy(SA2IP(addr), p_addr, SAIPLEN(addr));
              if (IN6_IS_ADDR_MULTICAST((struct in6_addr*)p))
                {
                  err = -1;
                  break;
                }
            }
          log_(NORM, "Found peer address %s in HDRR\n",
               logaddr(addr));
          err = 0;
        }
      location += tlv_length_to_parameter_length(length);
    }     /* end while */

  if (err < 0)
    {
      memset(addr, 0, sizeof(struct sockaddr_storage));
    }
  if (peer_hi)
    {
      free_hi_node(peer_hi);
    }
  return(err);
}
Ejemplo n.º 5
0
/*
 * \fn hip_dht_resolve_hi()
 *
 * \param hi	pointer to host identity whose name, LSI, or HIT can be used
 *              for lookups, and the HIT and address may be updated
 * \param retry if TRUE, we'll spawn a new thread an retry multiple times
 *              without blocking
 *
 * \return	returns -1 if there is a problem, 0 otherwise
 *
 * \brief Given a Host Identity, perform a DHT lookup using its HIT and store
 * any resulting address in the hi_node. If the HIT is missing, perform a HIT
 * lookup in the DHT using the name and/or LSI.
 */
int hip_dht_resolve_hi(hi_node *hi, int retry)
{
  int err;
  struct sockaddr_storage ss_addr;
  struct sockaddr *addr = (struct sockaddr*) &ss_addr;
  sockaddr_list *list;
  char hit_str[INET6_ADDRSTRLEN];
#ifndef __WIN32__
  pthread_attr_t attr;
  pthread_t thr;
#endif
  if (hip_dht_select_server(addr) < 0)
    {
      return(0);           /* prevents unneccessary thread creation */

    }
  /* When retry is turned on, a separate thread will be forked that
   * will perform the DHT lookup(s), retry a certain number of times,
   * and exit */
  if (retry == TRUE)
    {
#ifdef __WIN32__
      _beginthread(hip_dht_resolve_hi_thread, 0, (void *)hi);
#else
      pthread_attr_init(&attr);
      pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
      pthread_create(&thr, &attr, hip_dht_resolve_hi_thread, hi);
#endif
      return(0);
      /* We have been recursively called from a thread */
    }
  else if (retry == 2)
    {
      retry = TRUE;           /* used for calls below... */
    }

  /*
   * First locate the HIT using the peer's name if this HIT is missing.
   */
  if (hits_equal(hi->hit, zero_hit))
    {
      if (hi->name_len == 0)
        {
          log_(NORM,
               "HIT and name not present, unable to perform"
               " DHT lookup.\n");
          return(-1);
        }
      log_(NORM,
           "HIT not present for peer %s, performing DHT lookup "
           "using the name '%s'.\n",
           logaddr(SA(&hi->lsi)),
           hi->name);
      if ((err = hip_dht_lookup_hit_by_name(hi->name, &hi->hit,
                                            retry)) < 0)
        {
          /* no HIT from name, so we cannot do address lookup */
          log_(WARN, "Unable to find HIT for %s in the DHT.\n",
               logaddr(SA(&hi->lsi)));
          return(err);
        }
      else
        {
          hit_to_str(hit_str, hi->hit);
          log_(NORM, "Discovered HIT for peer %s using the DHT: "
               "%s\n", hi->name, hit_str);
        }
    }

  /*
   * Look up current IP address using HIT as key
   */
  memset(addr, 0, sizeof(struct sockaddr_storage));
  addr->sa_family = AF_INET;
  if ((err = hip_dht_lookup_address(&hi->hit, addr, retry)) < 0)
    {
      return(err);
    }

  /* add address to list, checking if first item is empty */
  pthread_mutex_lock(&hi->addrs_mutex);
  if ((hi->addrs.status == DELETED) || !VALID_FAM(&hi->addrs.addr))
    {
      memcpy(&hi->addrs.addr, addr, SALEN(addr));
      hi->addrs.if_index = 0;
      hi->addrs.lifetime = 0;
      hi->addrs.status = UNVERIFIED;
      hi->addrs.nonce = 0;
      gettimeofday(&hi->addrs.creation_time, NULL);
    }
  else
    {
      list = &hi->addrs;
      add_address_to_list(&list, addr, 0);
    }
  pthread_mutex_unlock(&hi->addrs_mutex);

  return(0);
}
Ejemplo n.º 6
0
/* Add (flagadd=1) or remove (flagadd=0) userhost from the subscriber
 * database table. Comment is e.g. the subscriber from line or name. It
 * is added to the log. Event is the action type, e.g. "probe",
 * "manual", etc. The direction (sub/unsub) is inferred from
 * flagadd. Returns 1 on success, 0 on failure. If forcehash is >=0 it
 * is used in place of the calculated hash. This makes it possible to
 * add addresses with a hash that does not exist. forcehash has to be
 * 0..99.  For unsubscribes, the address is only removed if forcehash
 * matches the actual hash. This way, ezmlm-manage can be prevented from
 * touching certain addresses that can only be removed by
 * ezmlm-unsub. Usually, this would be used for sublist addresses (to
 * avoid removal) and sublist aliases (to prevent users from subscribing
 * them (although the cookie mechanism would prevent the resulting
 * duplicate message from being distributed. */
int sub_sql_subscribe(struct subdbinfo *info,
		      const char *table,
		      const char *userhost,
		      int flagadd,
		      const char *comment,
		      const char *event,
		      int forcehash)
{
  void *result;
  char *cpat;
  char szhash[3] = "00";

  unsigned int j;
  unsigned char ch;
  int nparams;

  make_name(info,table?"_":0,table,0);

  /* lowercase and check address */
  stralloc_copys(&addr,userhost);
  if (addr.len > 255)			/* this is 401 in std ezmlm. 255 */
					/* should be plenty! */
    strerr_die2x(100,FATAL,MSG(ERR_ADDR_LONG));
  j = byte_rchr(addr.s,addr.len,'@');
  if (j == addr.len)
    strerr_die2x(100,FATAL,MSG(ERR_ADDR_AT));
  cpat = addr.s + j;
  case_lowerb(cpat + 1,addr.len - j - 1);

  if (forcehash < 0) {
    stralloc_copy(&lcaddr,&addr);
    case_lowerb(lcaddr.s,j);		/* make all-lc version of address */
    ch = subhashsa(&lcaddr);
  } else
    ch = (forcehash % 100);

  szhash[0] = '0' + ch / 10;		/* hash for sublist split */
  szhash[1] = '0' + (ch % 10);

  if (flagadd) {
    /* FIXME: LOCK TABLES name WRITE */
    stralloc_copys(&query,"SELECT address FROM ");
    stralloc_cat(&query,&name);
    stralloc_cats(&query," WHERE ");
    stralloc_cats(&query,sql_subscribe_select_where_defn);
    stralloc_copy(&params[0],&addr);
    result = sql_select(info,&query,1,params);
    if (sql_fetch_row(info,result,1,params)) {
      sql_free_result(info,result);
      /* FIXME: UNLOCK TABLES */
      return 0;			/* already subscribed */
    } else {			/* not there */
      sql_free_result(info,result);

      stralloc_copys(&query,"INSERT INTO ");
      stralloc_cat(&query,&name);
      stralloc_cats(&query," (address,hash) VALUES ");
      stralloc_cats(&query,sql_subscribe_list_values_defn);
      stralloc_copy(&params[0],&addr);
      stralloc_copys(&params[1],szhash);
      sql_exec(info,&query,2,params);
      /* FIXME: UNLOCK TABLES */
    }
  } else {							/* unsub */
    stralloc_copys(&query,"DELETE FROM ");
    stralloc_cat(&query,&name);
    stralloc_cats(&query," WHERE ");
    stralloc_copy(&params[0],&addr);
    if (forcehash >= 0) {
      stralloc_cats(&query,sql_subscribe_delete2_where_defn);
      stralloc_copys(&params[1],szhash);
      nparams = 2;
    }
    else {
      stralloc_cats(&query,sql_subscribe_delete1_where_defn);
      nparams = 1;
    }
    if (sql_exec(info,&query,1,params) == 0)
      return 0;			/* address wasn't there*/
  }

  /* log to subscriber log */
  /* INSERT INTO t_slog (address,edir,etype,fromline) */
  /* VALUES('address',{'+'|'-'},'etype','[comment]') */

  stralloc_copys(&query,"INSERT INTO ");
  stralloc_cat(&query,&name);
  stralloc_cats(&query,"_slog (address,edir,etype,fromline) VALUES ");
  stralloc_cats(&query,sql_subscribe_slog_values_defn);
  stralloc_copy(&params[0],&addr);
  stralloc_copys(&params[1],flagadd?"+":"-"); /* edir */
  stralloc_copyb(&params[2],event+1,!!*(event+1)); /* etype */
  stralloc_copys(&params[3],comment && *comment ? comment : ""); /* from */

  sql_exec(info,&query,4,params); /* log (ignore errors) */
  stralloc_0(&addr);
  logaddr(table,event,addr.s,comment);   /* also log to old log */
  return 1;				 /* desired effect */
}
Ejemplo n.º 7
0
/* Add (flagadd=1) or remove (flagadd=0) userhost from the subscriber
 * database table. Comment is e.g. the subscriber from line or name. It
 * is added to the log. Event is the action type, e.g. "probe",
 * "manual", etc. The direction (sub/unsub) is inferred from
 * flagadd. Returns 1 on success, 0 on failure. If forcehash is >=0 it
 * is used in place of the calculated hash. This makes it possible to
 * add addresses with a hash that does not exist. forcehash has to be
 * 0..99.  For unsubscribes, the address is only removed if forcehash
 * matches the actual hash. This way, ezmlm-manage can be prevented from
 * touching certain addresses that can only be removed by
 * ezmlm-unsub. Usually, this would be used for sublist addresses (to
 * avoid removal) and sublist aliases (to prevent users from subscribing
 * them (although the cookie mechanism would prevent the resulting
 * duplicate message from being distributed. */
static int _subscribe(struct subdbinfo *info,
                      const char *table,
                      const char *userhost,
                      int flagadd,
                      const char *comment,
                      const char *event,
                      int forcehash)
{
    sqlite3_stmt *stmt;
    char *cpat;
    char szhash[3] = "00";
    int res;

    unsigned int j;
    unsigned char ch;

    domain.len = 0;			/* clear domain */
    /* lowercase and check address */
    if (!stralloc_copys(&addr,userhost)) die_nomem();
    if (addr.len > 255)			/* this is 401 in std ezmlm. 255 */
        /* should be plenty! */
        strerr_die2x(100,FATAL,MSG(ERR_ADDR_LONG));
    j = byte_rchr(addr.s,addr.len,'@');
    if (j == addr.len)
        strerr_die2x(100,FATAL,MSG(ERR_ADDR_AT));
    cpat = addr.s + j;
    case_lowerb(cpat + 1,addr.len - j - 1);
    if (!stralloc_copy(&quoted, &addr)) die_nomem();
    /* stored unescaped, so it should be ok if quoted.len is >255, as */
    /* long as addr.len is not */

    if (forcehash < 0) {
        if (!stralloc_copy(&lcaddr,&addr)) die_nomem();
        case_lowerb(lcaddr.s,j);		/* make all-lc version of address */
        ch = subhashsa(&lcaddr);
    } else
        ch = (forcehash % 100);

    szhash[0] = '0' + ch / 10;		/* hash for sublist split */
    szhash[1] = '0' + (ch % 10);

    if (flagadd) {
        if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem();
        if (!stralloc_cat_table(&line,info,table)) die_nomem();
        if (!stralloc_cats(&line," WHERE address LIKE '")) die_nomem();
        if (!stralloc_cat(&line,&quoted)) die_nomem();	/* addr */
        if (!stralloc_cats(&line,"'")) die_nomem();
        if (!stralloc_0(&line)) die_nomem();

        if ((stmt = _sqlquery(info, &line)) == NULL)
            strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

        res = sqlite3_step(stmt);
        sqlite3_finalize(stmt);

        if (res == SQLITE_ROW)
            return 0;						/* there */
        else if (res != SQLITE_DONE)
        {
            strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));
        } else {							/* not there */
            if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem();
            if (!stralloc_cat_table(&line,info,table)) die_nomem();
            if (!stralloc_cats(&line," (address,hash) VALUES ('"))
                die_nomem();
            if (!stralloc_cat(&line,&quoted)) die_nomem();	/* addr */
            if (!stralloc_cats(&line,"',")) die_nomem();
            if (!stralloc_cats(&line,szhash)) die_nomem();	/* hash */
            if (!stralloc_cats(&line,")")) die_nomem();
            if (!stralloc_0(&line)) die_nomem();

            if ((stmt = _sqlquery(info, &line)) == NULL)
                strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

            if (sqlite3_step(stmt) != SQLITE_DONE)
                strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

            sqlite3_finalize(stmt);
        }
    } else {							/* unsub */
        if (!stralloc_copys(&line,"DELETE FROM ")) die_nomem();
        if (!stralloc_cat_table(&line,info,table)) die_nomem();
        if (!stralloc_cats(&line," WHERE address LIKE '")) die_nomem();
        if (!stralloc_cat(&line,&quoted)) die_nomem();	/* addr */
        if (forcehash >= 0) {
            if (!stralloc_cats(&line,"' AND hash=")) die_nomem();
            if (!stralloc_cats(&line,szhash)) die_nomem();
        } else {
            if (!stralloc_cats(&line,"' AND hash BETWEEN 0 AND 52"))
                die_nomem();
        }

        if (!stralloc_0(&line)) die_nomem();

        if ((stmt = _sqlquery(info, &line)) == NULL)
            strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

        if (sqlite3_step(stmt) != SQLITE_DONE)
            strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

        sqlite3_finalize(stmt);

        if (sqlite3_changes((sqlite3*)info->conn) == 0)
            return 0;				/* address wasn't there*/
    }

    /* log to subscriber log */
    /* INSERT INTO t_slog (address,edir,etype,fromline) */
    /* VALUES('address',{'+'|'-'},'etype','[comment]') */

    if (!stralloc_copys(&logline,"INSERT INTO ")) die_nomem();
    if (!stralloc_cat_table(&logline,info,table)) die_nomem();
    if (!stralloc_cats(&logline,
                       "_slog (tai,address,edir,etype,fromline) VALUES ("))
        die_nomem();
    if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,now()))) die_nomem();
    if (!stralloc_cats(&logline,",'")) die_nomem();
    if (!stralloc_cat(&logline,&quoted)) die_nomem();
    if (flagadd) {						/* edir */
        if (!stralloc_cats(&logline,"','+','")) die_nomem();
    } else {
        if (!stralloc_cats(&logline,"','-','")) die_nomem();
    }
    if (*(event + 1))	/* ezmlm-0.53 uses '' for ezmlm-manage's work */
        if (!stralloc_catb(&logline,event+1,1)) die_nomem();	/* etype */
    if (!stralloc_cats(&logline,"','")) die_nomem();
    if (comment && *comment) {
        j = str_len(comment);
        if (!stralloc_copys(&quoted, comment)) die_nomem();	/* from */
        if (!stralloc_cat(&logline,&quoted)) die_nomem();
    }
    if (!stralloc_cats(&logline,"')")) die_nomem();
    if (!stralloc_0(&logline)) die_nomem();

    if ((stmt = _sqlquery(info, &logline)) != NULL)
    {
        sqlite3_step(stmt);			/* log (ignore errors) */
        sqlite3_finalize(stmt);
    }

    if (!stralloc_0(&addr))
        ;				/* ignore errors */
    logaddr(table,event,addr.s,comment);	/* also log to old log */
    return 1;					/* desired effect */
}