Beispiel #1
0
int overlay_mdp_recv(overlay_mdp_frame *mdp, int port, int *ttl) 
{
  char mdp_socket_name[101];
  unsigned char recvaddrbuffer[1024];
  struct sockaddr *recvaddr=(struct sockaddr *)recvaddrbuffer;
  unsigned int recvaddrlen=sizeof(recvaddrbuffer);
  struct sockaddr_un *recvaddr_un;
  
  if (!FORM_SERVAL_INSTANCE_PATH(mdp_socket_name, "mdp.socket"))
    return WHY("Could not find mdp socket");
  mdp->packetTypeAndFlags=0;
  
  /* Check if reply available */
  set_nonblock(mdp_client_socket);
  ssize_t len = recvwithttl(mdp_client_socket,(unsigned char *)mdp, sizeof(overlay_mdp_frame),ttl,recvaddr,&recvaddrlen);
  set_block(mdp_client_socket);
  
  recvaddr_un=(struct sockaddr_un *)recvaddr;
  /* Null terminate received address so that the stat() call below can succeed */
  if (recvaddrlen<1024) recvaddrbuffer[recvaddrlen]=0;
  if (len>0) {
    /* Make sure recvaddr matches who we sent it to */
    if (strncmp(mdp_socket_name, recvaddr_un->sun_path, sizeof(recvaddr_un->sun_path))) {
      /* Okay, reply was PROBABLY not from the server, but on OSX if the path
       has a symlink in it, it is resolved in the reply path, but might not
       be in the request path (mdp_socket_name), thus we need to stat() and
       compare inode numbers etc */
      struct stat sb1,sb2;
      if (stat(mdp_socket_name,&sb1)) return WHY("stat(mdp_socket_name) failed, so could not verify that reply came from MDP server");
      if (stat(recvaddr_un->sun_path,&sb2)) return WHY("stat(ra->sun_path) failed, so could not verify that reply came from MDP server");
      if ((sb1.st_ino!=sb2.st_ino)||(sb1.st_dev!=sb2.st_dev))
	return WHY("Reply did not come from server");
    }
    
    // silently drop incoming packets for the wrong port number
    if (port>0 && port != mdp->in.dst.port){
      WARNF("Ignoring packet for port %d",mdp->in.dst.port);
      return -1;
    }
    
    int expected_len = overlay_mdp_relevant_bytes(mdp);
    
    if (len < expected_len){
      return WHYF("Expected packet length of %d, received only %lld bytes", expected_len, (long long) len);
    }
    
    /* Valid packet received */
    return 0;
  } else 
  /* no packet received */
    return -1;
  
}
Beispiel #2
0
int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr,int recvaddrlen,
			  overlay_mdp_frame *mdpreply)
{
  int replylen;

  if (!recvaddr) return 0;

  replylen=overlay_mdp_relevant_bytes(mdpreply);
  if (replylen<0) return WHY("Invalid MDP frame (could not compute length)");

  errno=0;
  int r=sendto(sock,(char *)mdpreply,replylen,0,
	       (struct sockaddr *)recvaddr,recvaddrlen);
  if (r<replylen) { 
    WHY_perror("sendto(d)"); 
    return WHYF("sendto() failed when sending MDP reply, sock=%d, r=%d", sock, r); 
  } else
    if (0) DEBUGF("reply of %d bytes sent",r);
  return 0;  
}
Beispiel #3
0
int overlay_saw_mdp_frame(overlay_mdp_frame *mdp, time_ms_t now)
{
  IN();
  int i;
  int match=-1;

  switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK) {
  case MDP_TX: 
    /* Regular MDP frame addressed to us.  Look for matching port binding,
       and if available, push to client.  Else do nothing, or if we feel nice
       send back a connection refused type message? Silence is probably the
       more prudent path.
    */

    if (debug & DEBUG_MDPREQUESTS) 
      DEBUGF("Received packet with listener (MDP ports: src=%s*:%d, dst=%d)",
	   alloca_tohex(mdp->out.src.sid, 7),
	   mdp->out.src.port,mdp->out.dst.port);

    // TODO pass in dest subscriber as an argument, we should know it by now
    struct subscriber *destination = NULL;
    if (!is_broadcast(mdp->out.dst.sid)){
      destination = find_subscriber(mdp->out.dst.sid, SID_SIZE, 1);
    }
    
    for(i=0;i<MDP_MAX_BINDINGS;i++)
      {
	if (mdp_bindings[i].port!=mdp->out.dst.port)
	  continue;
	
	if ((!destination) || mdp_bindings[i].subscriber == destination){
	  /* exact match, so stop searching */
	  match=i;
	  break;
	}else if (!mdp_bindings[i].subscriber){
	  /* If we find an "ANY" binding, remember it. But we will prefer an exact match if we find one */
	  match=i;
	}
      }
    
    if (match>-1) {
      struct sockaddr_un addr;

      bcopy(mdp_bindings[match].socket_name,addr.sun_path,mdp_bindings[match].name_len);
      addr.sun_family=AF_UNIX;
      errno=0;
      int len=overlay_mdp_relevant_bytes(mdp);
      int r=sendto(mdp_named.poll.fd,mdp,len,0,(struct sockaddr*)&addr,sizeof(addr));
      if (r==overlay_mdp_relevant_bytes(mdp)) {	
	RETURN(0);
      }
      WHY("didn't send mdp packet");
      if (errno==ENOENT) {
	/* far-end of socket has died, so drop binding */
	INFOF("Closing dead MDP client '%s'",mdp_bindings[match].socket_name);
	overlay_mdp_releasebindings(&addr,mdp_bindings[match].name_len);
      }
      WHY_perror("sendto(e)");
      RETURN(WHY("Failed to pass received MDP frame to client"));
    } else {
      /* No socket is bound, ignore the packet ... except for magic sockets */
      switch(mdp->out.dst.port) {
      case MDP_PORT_VOMP:
	RETURN(vomp_mdp_received(mdp));
      case MDP_PORT_KEYMAPREQUEST:
	/* Either respond with the appropriate SAS, or record this one if it
	   verifies out okay. */
	if (debug & DEBUG_MDPREQUESTS)
	  DEBUG("MDP_PORT_KEYMAPREQUEST");
	RETURN(keyring_mapping_request(keyring,mdp));
      case MDP_PORT_DNALOOKUP: /* attempt to resolve DID to SID */
	{
	  int cn=0,in=0,kp=0;
	  char did[64+1];
	  int pll=mdp->out.payload_length;
	  if (pll>64) pll=64;
	  /* get did from the packet */
	  if (mdp->out.payload_length<1) {
	    RETURN(WHY("Empty DID in DNA resolution request")); }
	  bcopy(&mdp->out.payload[0],&did[0],pll);
	  did[pll]=0;
	  
	  if (debug & DEBUG_MDPREQUESTS)
	    DEBUG("MDP_PORT_DNALOOKUP");
	  
	  int results=0;
	  while(keyring_find_did(keyring,&cn,&in,&kp,did))
	    {
	      /* package DID and Name into reply (we include the DID because
		 it could be a wild-card DID search, but the SID is implied 
		 in the source address of our reply). */
	      if (keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key_len > DID_MAXSIZE) 
		/* skip excessively long DID records */
		continue;
	      const unsigned char *packedSid = keyring->contexts[cn]->identities[in]->keypairs[0]->public_key;
	      const char *unpackedDid = (const char *) keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key;
	      const char *name = (const char *)keyring->contexts[cn]->identities[in]->keypairs[kp]->public_key;
	      // URI is sid://SIDHEX/DID
	      strbuf b = strbuf_alloca(SID_STRLEN + DID_MAXSIZE + 10);
	      strbuf_puts(b, "sid://");
	      strbuf_tohex(b, packedSid, SID_SIZE);
	      strbuf_puts(b, "/local/");
	      strbuf_puts(b, unpackedDid);
	      overlay_mdp_dnalookup_reply(&mdp->out.src, packedSid, strbuf_str(b), unpackedDid, name);
	      kp++;
	      results++;
	    }
	  if (!results) {
	    /* No local results, so see if servald has been configured to use
	       a DNA-helper that can provide additional mappings.  This provides
	       a generalised interface for resolving telephone numbers into URIs.
	       The first use will be for resolving DIDs to SIP addresses for
	       OpenBTS boxes run by the OTI/Commotion project. 

	       The helper is run asynchronously, and the replies will be delivered
	       when results become available, so this function will return
	       immediately, so as not to cause blockages and delays in servald.
	    */
	    dna_helper_enqueue(mdp, did, mdp->out.src.sid);
	    monitor_tell_formatted(MONITOR_DNAHELPER, "LOOKUP:%s:%d:%s\n", alloca_tohex_sid(mdp->out.src.sid), mdp->out.src.port, did);
	  }
	  RETURN(0);
	}
	break;
      case MDP_PORT_ECHO: /* well known ECHO port for TCP/UDP and now MDP */
	{
	  /* Echo is easy: we swap the sender and receiver addresses (and thus port
	     numbers) and send the frame back. */

	  /* Swap addresses */
	  overlay_mdp_swap_src_dst(mdp);

	  /* Prevent echo:echo connections and the resulting denial of service from triggering endless pongs. */
	  if (mdp->out.dst.port==MDP_PORT_ECHO) {
	    RETURN(WHY("echo loop averted"));
	  }
	  /* If the packet was sent to broadcast, then replace broadcast address
	     with our local address. For now just responds with first local address */
	  if (is_broadcast(mdp->out.src.sid))
	    {
	      if (my_subscriber)		  
		bcopy(my_subscriber->sid,
		      mdp->out.src.sid,SID_SIZE);
	      else
		/* No local addresses, so put all zeroes */
		bzero(mdp->out.src.sid,SID_SIZE);
	    }

	  /* queue frame for delivery */	  
	  overlay_mdp_dispatch(mdp,0 /* system generated */,
			       NULL,0);
	  
	  /* and switch addresses back around in case the caller was planning on
	     using MDP structure again (this happens if there is a loop-back reply
	     and the frame needs sending on, as happens with broadcasts.  MDP ping
	     is a simple application where this occurs). */
	  overlay_mdp_swap_src_dst(mdp);
	  
	}
	break;
      default:
	/* Unbound socket.  We won't be sending ICMP style connection refused
	   messages, partly because they are a waste of bandwidth. */
	RETURN(WHYF("Received packet for which no listening process exists (MDP ports: src=%d, dst=%d",
		    mdp->out.src.port,mdp->out.dst.port));
      }
    }
    break;
  default:
    RETURN(WHYF("We should only see MDP_TX frames here (MDP message type = 0x%x)",
		mdp->packetTypeAndFlags));
  }

  RETURN(0);
}
Beispiel #4
0
static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame *mdp, time_ms_t now)
{
  IN();
  int i;
  int match=-1;

  switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK) {
  case MDP_TX: 
    /* Regular MDP frame addressed to us.  Look for matching port binding,
       and if available, push to client.  Else do nothing, or if we feel nice
       send back a connection refused type message? Silence is probably the
       more prudent path.
    */

    if (config.debug.mdprequests) 
      DEBUGF("Received packet with listener (MDP ports: src=%s*:%d, dst=%d)",
	   alloca_tohex(mdp->out.src.sid, 7),
	   mdp->out.src.port,mdp->out.dst.port);

    // TODO pass in dest subscriber as an argument, we should know it by now
    struct subscriber *destination = NULL;
    if (frame)
      destination = frame->destination;
    else if (!is_sid_broadcast(mdp->out.dst.sid)){
      destination = find_subscriber(mdp->out.dst.sid, SID_SIZE, 1);
    }
    
    for(i=0;i<MDP_MAX_BINDINGS;i++)
      {
	if (mdp_bindings[i].port!=mdp->out.dst.port)
	  continue;
	
	if ((!destination) || mdp_bindings[i].subscriber == destination){
	  /* exact match, so stop searching */
	  match=i;
	  break;
	}else if (!mdp_bindings[i].subscriber){
	  /* If we find an "ANY" binding, remember it. But we will prefer an exact match if we find one */
	  match=i;
	}
      }
    
    if (match>-1) {
      struct sockaddr_un addr;

      bcopy(mdp_bindings[match].socket_name,addr.sun_path,mdp_bindings[match].name_len);
      addr.sun_family=AF_UNIX;
      errno=0;
      int len=overlay_mdp_relevant_bytes(mdp);
      int r=sendto(mdp_named.poll.fd,mdp,len,0,(struct sockaddr*)&addr,sizeof(addr));
      if (r==overlay_mdp_relevant_bytes(mdp)) {	
	RETURN(0);
      }
      WHY("didn't send mdp packet");
      if (errno==ENOENT) {
	/* far-end of socket has died, so drop binding */
	INFOF("Closing dead MDP client '%s'",mdp_bindings[match].socket_name);
	overlay_mdp_releasebindings(&addr,mdp_bindings[match].name_len);
      }
      WHY_perror("sendto(e)");
      RETURN(WHY("Failed to pass received MDP frame to client"));
    } else {
      /* No socket is bound, ignore the packet ... except for magic sockets */
      RETURN(overlay_mdp_try_interal_services(frame, mdp));
    }
    break;
  default:
    RETURN(WHYF("We should only see MDP_TX frames here (MDP message type = 0x%x)",
		mdp->packetTypeAndFlags));
  }

  RETURN(0);
  OUT();
}
Beispiel #5
0
int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms)
{
  int len=4;
  
  if (mdp_client_socket==-1) 
    if (overlay_mdp_client_init() != 0)
      return -1;
  
  /* Minimise frame length to save work and prevent accidental disclosure of
   memory contents. */
  len=overlay_mdp_relevant_bytes(mdp);
  if (len<0) return WHY("MDP frame invalid (could not compute length)");
  
  /* Construct name of socket to send to. */
  struct sockaddr_un name;
  name.sun_family = AF_UNIX;
  if (!FORM_SERVAL_INSTANCE_PATH(name.sun_path, "mdp.socket"))
    return -1;
  
  set_nonblock(mdp_client_socket);
  int result=sendto(mdp_client_socket, mdp, len, 0,
		    (struct sockaddr *)&name, sizeof(struct sockaddr_un));
  set_block(mdp_client_socket);
  if (result<0) {
    mdp->packetTypeAndFlags=MDP_ERROR;
    mdp->error.error=1;
    snprintf(mdp->error.message,128,"Error sending frame to MDP server.");
    return WHY_perror("sendto(f)");
  } else {
    if (!(flags&MDP_AWAITREPLY)) {       
      return 0;
    }
  }
  
  int port=0;
  if ((mdp->packetTypeAndFlags&MDP_TYPE_MASK) == MDP_TX)
      port = mdp->out.src.port;
      
  time_ms_t started = gettime_ms();
  while(timeout_ms>=0 && overlay_mdp_client_poll(timeout_ms)>0){
    int ttl=-1;
    if (!overlay_mdp_recv(mdp, port, &ttl)) {
      /* If all is well, examine result and return error code provided */
      if ((mdp->packetTypeAndFlags&MDP_TYPE_MASK)==MDP_ERROR)
	return mdp->error.error;
      else
      /* Something other than an error has been returned */
	return 0;
    }
    
    // work out how much longer we can wait for a valid response
    time_ms_t now = gettime_ms();
    timeout_ms -= (now - started);
  }
  
  /* Timeout */
  mdp->packetTypeAndFlags=MDP_ERROR;
  mdp->error.error=1;
  snprintf(mdp->error.message,128,"Timeout waiting for reply to MDP packet (packet was successfully sent).");    
  return -1; /* WHY("Timeout waiting for server response"); */
}