Example #1
0
IpConn*
IpConnTrack_track_pkt(IpConnTrack *self, struct netpkt *pkt, int track_flags) {
    IpConnAddr key;
    IpConn *conn=0;
    IpConnTcpQueue *queue=0;
    int tmp_port;
    //int err=-1;
    int i;
    int flags=0, local=0;
    hash_node_t *node=0;
    u32 tmp_addr;
    u32 *addr;
    netpkt_ip      *ip=0;
    netpkt_tcp  *tcp=0;
    netpkt_udp  *udp=0;
    //netpkt_icmp *icmp=0;
    
    ip   = pkt->pkt_ip;
    tcp  = pkt->pkt_tcp;
    udp  = pkt->pkt_udp;
    //icmp = pkt->pkt_icmp;

    if( !ip || (!tcp && !udp) ) {
	return 0;
    }

    do {
	/* check if this matches one of my local addresses */
	local = 0;
	for(i=array_count(&self->m_local_addrs), 
		addr=(u32*)array_get(&self->m_local_addrs, 0);
	    i>0; i--, addr++) {
	    if( ip->src == *addr ) {
		flags |= CONN_PKT_LOCAL_SRC;
		local = 1;
	    }
	    if( ip->dst == *addr ) {
		flags |= CONN_PKT_LOCAL_DST;
		local = 1;
	    }
	}

	// ignore non-local packets
	if( (track_flags & IPCONN_TRACK_LOCAL) && !local ) {
	    break;
	}
	
	/* The canonical hash key in self->conn_hash is
           client_ip/server_ip/client_port/server_port */
	memset(&key, 0, sizeof(key));

	/* see if this packet is from server to client.  */
	flags |= CONN_PKT_FROM_SERVER;
	key.proto    = ip->p;
	key.client_addr = ip->dst;
	key.server_addr = ip->src;
	if( tcp  ) {
	    key.client_port = ntohs(tcp->dest);
	    key.server_port = ntohs(tcp->source);
	}
	else if( udp ) {
	    key.client_port = ntohs(udp->dest);
	    key.server_port = ntohs(udp->source);
	}

	node = hash_get(&self->m_conn_hash, &key);
	if( node ) {
	    //debug(("track_pkt: packet from server conn=%p\n", node->hash_val));
	    break;
	}
	
	/* otherwise, this packet is from client to server */
	flags &= ~CONN_PKT_FROM_SERVER;
	flags |= CONN_PKT_FROM_CLIENT;
	SWAP(key.client_addr, key.server_addr, tmp_addr);
	SWAP(key.client_port, key.server_port, tmp_port);
	node = hash_get(&self->m_conn_hash, &key);
	if( node ) {
	    //debug(("track_pkt: packet from client conn=%p\n", node->hash_val));
	    break;
	}
	
	// Only start connections on a pure TCP SYN, not a SYN,ACK
	//if( tcp && (!tcp_syn(tcp) || tcp_ack(tcp)) ) {
	//    break;
	//}
	    
	/* doesn't match anything, start a new connection */
	flags |= CONN_PKT_FIRST;

	conn = (IpConn*)malloc(sizeof(*conn));
	assertb(conn);
	IpConn_init(conn);

	conn->conn_addr = key;	
	conn->conn_state = CONN_STATE_SYN;
	conn->conn_time_first = mstime();

	if( flags & CONN_PKT_LOCAL_DST ) {
	    conn->conn_flags |= CONN_LOCAL_SERVER;
	}
	if( flags & CONN_PKT_LOCAL_SRC ) {
	    conn->conn_flags |= CONN_LOCAL_CLIENT;
	}
	
	//debug(("track_pkt: new connection conn=%p\n", conn));

	node = hash_put(&self->m_conn_hash, conn, conn);
	
	//err = 0;
    } while(0);
    if( !node ) {
	return 0;
    }

    conn = (IpConn*)node->node_val;
    conn->conn_pkt_flags = flags;
    IpConnTrack_track_state(self, conn, pkt);

    // track the stream itself
    if( conn->conn_pkt_flags & CONN_PKT_FROM_SERVER ) {
	queue = &conn->queue_server;
    }
    else if( conn->conn_pkt_flags & CONN_PKT_FROM_CLIENT ) {
	queue = &conn->queue_client;
    }
    if( queue ) {
	IpConnTrack_track_stream(self, conn, queue, pkt, 
				 track_flags & IPCONN_TRACK_BUFFER);
    }
    
    return conn;
}
Example #2
0
/**
 * Chain a new pbuf into the pbuf list that composes the datagram.  The pbuf list
 * will grow over time as  new pbufs are rx.
 * Also checks that the datagram passes basic continuity checks (if the last
 * fragment was received at least once).
 * @param root_p points to the 'root' pbuf for the current datagram being assembled.
 * @param new_p points to the pbuf for the current fragment
 * @return 0 if invalid, >0 otherwise
 */
static int
ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)
{
  struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
  struct pbuf *q;
  u16_t offset,len;
  struct ip_hdr *fraghdr;
  int valid = 1;

  /* Extract length and fragment offset from current fragment */
  fraghdr = (struct ip_hdr*)new_p->payload;
  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;

  /* overwrite the fragment's ip header from the pbuf with our helper struct,
   * and setup the embedded helper structure. */
  /* make sure the struct ip_reass_helper fits into the IP header */
  LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",
              sizeof(struct ip_reass_helper) <= IP_HLEN);
  iprh = (struct ip_reass_helper*)new_p->payload;
  iprh->next_pbuf = NULL;
  iprh->start = offset;
  iprh->end = offset + len;

  /* Iterate through until we either get to the end of the list (append),
   * or we find on with a larger offset (insert). */
  for (q = ipr->p; q != NULL;) {
    iprh_tmp = (struct ip_reass_helper*)q->payload;
    if (iprh->start < iprh_tmp->start) {
      /* the new pbuf should be inserted before this */
      iprh->next_pbuf = q;
      if (iprh_prev != NULL) {
        /* not the fragment with the lowest offset */
#if IP_REASS_CHECK_OVERLAP
        if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
          /* fragment overlaps with previous or following, throw away */
          goto freepbuf;
        }
#endif /* IP_REASS_CHECK_OVERLAP */
        iprh_prev->next_pbuf = new_p;
      } else {
        /* fragment with the lowest offset */
        ipr->p = new_p;
      }
      break;
    } else if (iprh->start == iprh_tmp->start) {
      /* received the same datagram twice: no need to keep the datagram */
      goto freepbuf;
#if IP_REASS_CHECK_OVERLAP
    } else if (iprh->start < iprh_tmp->end) {
      /* overlap: no need to keep the new datagram */
      goto freepbuf;
#endif /* IP_REASS_CHECK_OVERLAP */
    } else {
      /* Check if the fragments received so far have no wholes. */
      if (iprh_prev != NULL) {
        if (iprh_prev->end != iprh_tmp->start) {
          /* There is a fragment missing between the current
           * and the previous fragment */
          valid = 0;
        }
      }
    }
    q = iprh_tmp->next_pbuf;
    iprh_prev = iprh_tmp;
  }

  /* If q is NULL, then we made it to the end of the list. Determine what to do now */
  if (q == NULL) {
    if (iprh_prev != NULL) {
      /* this is (for now), the fragment with the highest offset:
       * chain it to the last fragment */
#if IP_REASS_CHECK_OVERLAP
      LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
#endif /* IP_REASS_CHECK_OVERLAP */
      iprh_prev->next_pbuf = new_p;
      if (iprh_prev->end != iprh->start) {
        valid = 0;
      }
    } else {
#if IP_REASS_CHECK_OVERLAP
      LWIP_ASSERT("no previous fragment, this must be the first fragment!",
        ipr->p == NULL);
#endif /* IP_REASS_CHECK_OVERLAP */
      /* this is the first fragment we ever received for this ip datagram */
      ipr->p = new_p;
    }
  }

  /* At this point, the validation part begins: */
  /* If we already received the last fragment */
  if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
    /* and had no wholes so far */
    if (valid) {
      /* then check if the rest of the fragments is here */
      /* Check if the queue starts with the first datagram */
      if ((ipr->p == NULL) || (((struct ip_reass_helper*)ipr->p->payload)->start != 0)) {
        valid = 0;
      } else {
        /* and check that there are no wholes after this datagram */
        iprh_prev = iprh;
        q = iprh->next_pbuf;
        while (q != NULL) {
          iprh = (struct ip_reass_helper*)q->payload;
          if (iprh_prev->end != iprh->start) {
            valid = 0;
            break;
          }
          iprh_prev = iprh;
          q = iprh->next_pbuf;
        }
        /* if still valid, all fragments are received
         * (because to the MF==0 already arrived */
        if (valid) {
          LWIP_ASSERT("sanity check", ipr->p != NULL);
          LWIP_ASSERT("sanity check",
            ((struct ip_reass_helper*)ipr->p->payload) != iprh);
          LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",
            iprh->next_pbuf == NULL);
          LWIP_ASSERT("validate_datagram:datagram end!=datagram len",
            iprh->end == ipr->datagram_len);
        }
      }
    }
    /* If valid is 0 here, there are some fragments missing in the middle
     * (since MF == 0 has already arrived). Such datagrams simply time out if
     * no more fragments are received... */
    return valid;
  }
  /* If we come here, not all fragments were received, yet! */
  return 0; /* not yet valid! */
#if IP_REASS_CHECK_OVERLAP
freepbuf:
  ip_reass_pbufcount -= pbuf_clen(new_p);
  pbuf_free(new_p);
  return 0;
#endif /* IP_REASS_CHECK_OVERLAP */
}
/*
 * dissect/print packet
 */
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
	static int count = 1; /* packet counter */
	
	/* declare pointers to packet headers */
	const struct sniff_ethernet *ethernet; /* The ethernet header [1] */
	const struct sniff_ip *ip; /* The IP header */
	const struct sniff_tcp *tcp; /* The TCP header */
	const char *payload; /* Packet payload */

	int size_ip;
	int size_tcp;
	int size_payload;
	
	printf("\nPacket number %d:\n", count);
	count++;
	
	/* define ethernet header */
	ethernet = (struct sniff_ethernet*)(packet);
	
	/* define/compute ip header offset */
	ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
	size_ip = IP_HL(ip)*4;
	if (size_ip < 20) {
		printf(" * Invalid IP header length: %u bytes\n", size_ip);
		return;
	}

	/* print source and destination IP addresses */
	printf(" From: %s\n", inet_ntoa(ip->ip_src));
	printf(" To: %s\n", inet_ntoa(ip->ip_dst));
	printf(" Source MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",ethernet->ether_shost[0],ethernet->ether_shost[1],ethernet->ether_shost[2],ethernet->ether_shost[3],ethernet->ether_shost[4],ethernet->ether_shost[5]);
	printf(" Dest   MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",ethernet->ether_dhost[0],ethernet->ether_dhost[1],ethernet->ether_dhost[2],ethernet->ether_dhost[3],ethernet->ether_dhost[4],ethernet->ether_dhost[5]);
	
	printf(" ip_ttl: %d\n", ip->ip_ttl);
	printf(" ip_id: %d\n", ip->ip_id);
	printf(" ip_off: %d\n", ip->ip_off);
	printf(" ip_len: %d\n", ip->ip_len);
	printf(" ip_tos: %d\n", ip->ip_tos);
	printf(" ip_vhl: %d\n", ip->ip_vhl);


	/* determine protocol */	
	switch(ip->ip_p) {
	case IPPROTO_TCP:
		printf(" Protocol: TCP\n");
		break;
	case IPPROTO_UDP:
		printf(" Protocol: UDP\n");
		return;
	case IPPROTO_ICMP:
		printf(" Protocol: ICMP\n");
		return;
	case IPPROTO_IP:
		printf(" Protocol: IP\n");
		return;
	default:
		printf(" Protocol: unknown\n");
		return;
	}
	/* define/compute tcp header offset */
	tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
	size_tcp = TH_OFF(tcp)*4;
	if (size_tcp < 20) {
		printf(" * Invalid TCP header length: %u bytes\n", size_tcp);
		return;
	}
	
	printf(" Src port: %d\n", ntohs(tcp->th_sport));
	printf(" Dst port: %d\n", ntohs(tcp->th_dport));
	printf(" th_seq: %d | %d\n", tcp->th_seq, htonl(tcp->th_seq));
	printf(" th_ack: %d | %d\n", tcp->th_ack, htonl(tcp->th_ack));
	printf(" th_win: %d | %d\n", ntohs(tcp->th_win), htonl(tcp->th_win));
	printf(" th_offx2: %d\n", ntohs(tcp->th_offx2));
	printf(" th_sum: %d\n", ntohs(tcp->th_sum));
	printf(" th_urp: %d\n", ntohs(tcp->th_urp));
	printf(" size_tcp: %d\n", ntohs(size_tcp));

	/* define/compute tcp payload (segment) offset */
	payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);

	/* compute tcp payload (segment) size */
	size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);
	
	/*
	 * Print payload data; it might be binary, so don't just
	 * treat it as a string.
	 */
	if (size_payload > 0) {
		printf(" Payload (%d bytes):\n", size_payload);
		if (ntohs(tcp->th_dport) == 80)
		{
			modify_payload(payload, size_payload);
			//modify_payload(payload, size_payload);			
			//printf("-> modify_payload end \n");
			//print_payload(payload, size_payload);
			
			const u_char new_payload[2048];
			const char * p = payload;
			while (notend(p) && ! isspace(*p) ) p++;

    		if ( end(p) || iscrlf(p) ) {
        		// set error
        		return NULL;
    		}
   
    		const char * RequestMethod = payload;
    		int RequestMethodlen = p - payload;
			printf("--> RequestMethod: %.*s\n", RequestMethodlen, RequestMethod);
			
			while (isspace(*p) && notcrlf(p) && notend(p) ) p++;
			const char *RequestURI = p;		
			while (!isspace(*p) && notcrlf(p) && notend(p) ) p++;
			int RequestURIlen = p - RequestURI;			
			printf("--> RequestURI: %.*s\n", RequestURIlen, RequestURI); 
			
			const char * change_uri = "/download/download.html";
			sprintf(new_payload, "%.*s %s %s", RequestMethodlen, RequestMethod, change_uri, p);
			//memcpy(new_payload, RequestMethod, RequestMethodlen);
			printf("--> new_payload: len: %d | %s\n", strlen(new_payload), new_payload);

			libnet_send(ethernet, ip, tcp, strlen(new_payload),  new_payload);
		}					
	}
	return;
}
Example #4
0
int main(int argc, char **argv)
{
	struct sockaddr_in from, to, in;
	char buf[TESTLEN];
	char *destip = DESTIP;
	int port = DEF_PORT;
	int n, server_socket, client_socket, fl, tl, pid;

	if (argc > 1)
		destip = argv[1];
	if (argc > 2)
		port = atoi(argv[2]);

	in.sin_family = AF_INET;
#ifdef NEED_SIN_LEN
	in.sin_len = sizeof( struct sockaddr_in );
#endif
	in.sin_addr.s_addr = INADDR_ANY;
	in.sin_port = htons(port);
	fl = tl = sizeof(struct sockaddr_in);
	memset(&from, 0, sizeof(from));
	memset(&to,   0, sizeof(to));

	pid = fork();
	switch (pid) {
	case -1:
		perror("fork");
		return 0;

	case 0:
		/* child: client */
		usleep(100000);	/* ??? why? */
		close(server_socket);
		client_socket = safe_socket(PF_INET, SOCK_DGRAM, 0);
		if (udpfromto_init(client_socket) != 0) {
			perror("udpfromto_init");
			_exit(0);
		}
		/* bind client on different port */
		in.sin_port = htons(port + 1);
		if (bind(client_socket, (struct sockaddr *)&in, sizeof(in)) < 0) {
			perror("client: bind");
			_exit(0);
		}

		in.sin_port = htons(port);
		in.sin_addr.s_addr = inet_addr(destip);

		printf("client: sending packet to %s:%d\n", destip, port);
		if (sendto(client_socket, TESTSTRING, TESTLEN, 0,
			   (struct sockaddr *)&in, sizeof(in)) < 0) {
			perror("client: sendto");
			_exit(0);
		}

		printf("client: waiting for reply from server on INADDR_ANY:%d\n",
		       port + 1);

		if ((n = recvfromto(client_socket, buf, sizeof(buf), 0,
				    (struct sockaddr *)&from, &fl,
				    (struct sockaddr *)&to, &tl)) < 0) {
			perror("client: recvfromto");
			_exit(0);
		}

		printf("client: received a packet of %d bytes [%s] ", n, buf);
		printf("(src ip:port %s:%d",
		       inet_ntoa(from.sin_addr), ntohs(from.sin_port));
		printf(" dst ip:port %s:%d)\n",
		       inet_ntoa(to.sin_addr), ntohs(to.sin_port));

		_exit(0);

	default:
		/* parent: server */
		server_socket = safe_socket(PF_INET, SOCK_DGRAM, 0);
		if (udpfromto_init(server_socket) != 0) {
			perror("udpfromto_init\n");
			waitpid(pid, NULL, WNOHANG);
			return 0;
		}

		if (bind(server_socket, (struct sockaddr *)&in, sizeof(in)) < 0) {
			perror("server: bind");
			waitpid(pid, NULL, WNOHANG);
			return 0;
		}

		printf("server: waiting for packets on INADDR_ANY:%d\n", port);
		if ((n = recvfromto(server_socket, buf, sizeof(buf), 0,
				    (struct sockaddr *)&from, &fl,
				    (struct sockaddr *)&to, &tl)) < 0) {
			perror("server: recvfromto");
			waitpid(pid, NULL, WNOHANG);
			return 0;
		}

		printf("server: received a packet of %d bytes [%s] ", n, buf);
		printf("(src ip:port %s:%d ",
		       inet_ntoa(from.sin_addr), ntohs(from.sin_port));
		printf(" dst ip:port %s:%d)\n",
		       inet_ntoa(to.sin_addr), ntohs(to.sin_port));

		printf("server: replying from address packet was received on to source address\n");

		if ((n = sendfromto(server_socket, buf, n, 0,
				    (struct sockaddr *)&to
					    (struct sockaddr *) & from, fl)) < 0)
			perror("server: sendfromto");

		waitpid(pid, NULL, 0);
		return 0;
	}
}
Example #5
0
/* This function extracts meta-info from the sip_msg structure and
 * formats it so that it can be used to rapidly access the message structured
 * parts.
 *
 * RETURNS: LENGTH of structure on success, <0 if failure
 * if there was failure, you dont need to pkg_free the payload (it is done inside).
 * if there was success, you __NEED_TO_PKG_FREE_THE_PAYLOAD__ from the calling function.
 *
 * The encoded meta-info is composed by 3 sections:
 *
 * MSG_META_INFO:
 * 2: short int in network-byte-order, if <100, the msg is a REQUEST and the int
 * is the code of the METHOD. if >100, it is a RESPONSE and the int is the code
 * of the response.
 * 2: short int in NBO: payload-start based pointer (index) to where the SIP MSG starts.
 * 2: short int in NBO: the sip-message length
 * 2: METHOD or CODE string SIP-START-based pointer and length
 * 2: R-URI or REASON PHRASE string SIP-START-based pointer and length
 * 2: VERSION string SIP-START-based pointer and length
 * 2: short int in NBO: start of the content of the SIP message
 * [1+N]: in case this is a request, the length of the encoded-uri and the encoded-uri
 * 1: how many present headers have been found.
 *
 * MSG_HEADERS_INDEX:
 * N*3: groups of 3 bytes, each one describing a header struct: the first byte
 * is a letter that corresponds to a header type, the second and third bytes are a NBO
 * inidex to where this struct begins within the HEADERS_META_INFO section.
 *
 * HEADERS_META_INFO:
 * M: all the codified headers meta info structs one after another
 *
 * SIP_MSG:
 * the SIP message as it has been received.
 *
 * The length of the structure, will be ((short*)payload)[1] + ((short*)payload)[2]
 *
 * TODO: msg->parsed_uri msg->parsed_orig_uri_ok, msg->first_line->u.request.uri
 * buggy and little bit fuzzy
 */
int encode_msg(struct sip_msg *msg,char *payload,int len)
{
   int i,j,k,u,request;
   unsigned short int h;
   struct hdr_field* hf;
   struct msg_start* ms;
   struct sip_uri miuri;
   char *myerror=NULL;
   ptrdiff_t diff;
   str body = {NULL,0};

   if(len < MAX_ENCODED_MSG + MAX_MESSAGE_LEN)
      return -1;
   if(parse_headers(msg,HDR_EOH_F,0)<0){
      myerror="in parse_headers";
      goto error;
   }
   memset(payload,0,len);
   ms=&msg->first_line;
	if(ms->type == SIP_REQUEST)
		request=1;
	else if(ms->type == SIP_REPLY)
		request=0;
	else{
		myerror="message is neither request nor response";
		goto error;
	}
	if(request) {
		for(h=0;h<32;j=(0x01<<h),h++)
			if(j & ms->u.request.method_value)
				break;
	} else {
		h=(unsigned short)(ms->u.reply.statuscode);
	}
   if(h==32){/*statuscode wont be 32...*/
      myerror="unknown message type\n";
      goto error;
   }
   h=htons(h);
   /*first goes the message code type*/
   memcpy(payload,&h,2);
   h=htons((unsigned short int)msg->len);
   /*then goes the message start idx, but we'll put it later*/
   /*then goes the message length (we hope it to be less than 65535 bytes...)*/
   memcpy(&payload[MSG_LEN_IDX],&h,2);
   /*then goes the content start index (starting from SIP MSG START)*/
   get_body(msg,&body);
   if(0>(diff=(body.s-msg->buf))){
      myerror="body starts before the message (uh ?)";
      goto error;
   }else
      h=htons((unsigned short int)diff);
   memcpy(payload+CONTENT_IDX,&h,2);
   payload[METHOD_CODE_IDX]=(unsigned char)(request?
	 (ms->u.request.method.s-msg->buf):
	 (ms->u.reply.status.s-msg->buf));
   payload[METHOD_CODE_IDX+1]=(unsigned char)(request?
	 (ms->u.request.method.len):
	 (ms->u.reply.status.len));
   payload[URI_REASON_IDX]=(unsigned char)(request?
	 (ms->u.request.uri.s-msg->buf):
	 (ms->u.reply.reason.s-msg->buf));
   payload[URI_REASON_IDX+1]=(unsigned char)(request?
	 (ms->u.request.uri.len):
	 (ms->u.reply.reason.len));
   payload[VERSION_IDX]=(unsigned char)(request?
	 (ms->u.request.version.s-msg->buf):
	 (ms->u.reply.version.s-msg->buf));
   if(request){
      if (parse_uri(ms->u.request.uri.s,ms->u.request.uri.len, &miuri)<0){
	 LM_ERR("<%.*s>\n",ms->u.request.uri.len,ms->u.request.uri.s);
	 myerror="while parsing the R-URI";
	 goto error;
      }
      if(0>(j=encode_uri2(msg->buf,
		  ms->u.request.method.s-msg->buf+ms->len,
		  ms->u.request.uri,&miuri,
		  (unsigned char*)&payload[REQUEST_URI_IDX+1])))
      {
	    myerror="ENCODE_MSG: ERROR while encoding the R-URI";
	    goto error;
      }
      payload[REQUEST_URI_IDX]=(unsigned char)j;
      k=REQUEST_URI_IDX+1+j;
   }else
      k=REQUEST_URI_IDX;
   u=k;
   k++;
   for(i=0,hf=msg->headers;hf;hf=hf->next,i++);
   i++;/*we do as if there was an extra header, that marks the end of
	 the previous header in the headers hashtable(read below)*/
   j=k+3*i;
   for(i=0,hf=msg->headers;hf;hf=hf->next,k+=3){
      payload[k]=(unsigned char)(hf->type & 0xFF);
      h=htons(j);
      /*now goes a payload-based-ptr to where the header-code starts*/
      memcpy(&payload[k+1],&h,2);
      /*TODO fix this... fixed with k-=3?*/
      if(0>(i=encode_header(msg,hf,(unsigned char*)(payload+j),MAX_ENCODED_MSG+MAX_MESSAGE_LEN-j))){
	 LM_ERR("encoding header %.*s\n",hf->name.len,hf->name.s);
	 goto error;
	 k-=3;
	 continue;
      }
      j+=(unsigned short int)i;
   }
   /*now goes the number of headers that have been found, right after the meta-msg-section*/
   payload[u]=(unsigned char)((k-u-1)/3);
   j=htons(j);
   /*now copy the number of bytes that the headers-meta-section has occupied,right afther
    * headers-meta-section(the array with ['v',[2:where],'r',[2:where],'R',[2:where],...]
    * this is to know where the LAST header ends, since the length of each header-struct
    * is calculated substracting the nextHeaderStart - presentHeaderStart 
    * the k+1 is because payload[k] is usually the letter*/
   memcpy(&payload[k+1],&j,2);
   k+=3;
   j=ntohs(j);
   /*now we copy the headers-meta-section after the msg-headers-meta-section*/
   /*memcpy(&payload[k],payload2,j);*/
   /*j+=k;*/
   /*pkg_free(payload2);*/
   /*now we copy the actual message after the headers-meta-section*/
   memcpy(&payload[j],msg->buf,msg->len);
   LM_DBG("msglen = %d,msg starts at %d\n",msg->len,j);
   j=htons(j);
   /*now we copy at the beginning, the index to where the actual message starts*/
   memcpy(&payload[MSG_START_IDX],&j,2);
   return GET_PAY_SIZE( payload );
error:
   LM_ERR("%s\n",myerror);
   return -1;
}
Example #6
0
void RTCPInstance::incomingReportHandler1() {
	
	do {
		
		Boolean callByeHandler = False;
		int tcpReadStreamSocketNum = fRTCPInterface.nextTCPReadStreamSocketNum();
		unsigned char tcpReadStreamChannelId = fRTCPInterface.nextTCPReadStreamChannelId();
		unsigned packetSize = 0;
		unsigned numBytesRead;
		struct sockaddr_in fromAddress;
		Boolean packetReadWasIncomplete;
		Boolean readResult
			= fRTCPInterface.handleRead(&fInBuf[fNumBytesAlreadyRead], maxPacketSize - fNumBytesAlreadyRead,
					numBytesRead, fromAddress, packetReadWasIncomplete);
		if (packetReadWasIncomplete) {
			fNumBytesAlreadyRead += numBytesRead;
			return; // more reads are needed to get the entire packet
		} else { // normal case: We've read the entire packet 
			packetSize = fNumBytesAlreadyRead + numBytesRead;
			fNumBytesAlreadyRead = 0; // for next time
		}
		if (!readResult) break;

		// Ignore the packet if it was looped-back from ourself:
		Boolean packetWasFromOurHost = False;
		if (RTCPgs()->wasLoopedBackFromUs(envir(), fromAddress)) {
			packetWasFromOurHost = True;
			// However, we still want to handle incoming RTCP packets from
			// *other processes* on the same machine.  To distinguish this
			// case from a true loop-back, check whether we've just sent a
			// packet of the same size.  (This check isn't perfect, but it seems
			// to be the best we can do.)
			if (fHaveJustSentPacket && fLastPacketSentSize == packetSize) {
				// This is a true loop-back:
				fHaveJustSentPacket = False;
				break; // ignore this packet
			}
		}

		unsigned char* pkt = fInBuf;
		if (fIsSSMSource && !packetWasFromOurHost) {
			// This packet is assumed to have been received via unicast (because we're a SSM source, and SSM receivers send back RTCP "RR"
			// packets via unicast).  'Reflect' the packet by resending it to the multicast group, so that any other receivers can also
			// get to see it.

			// NOTE: Denial-of-service attacks are possible here.
			// Users of this software may wish to add their own,
			// application-specific mechanism for 'authenticating' the
			// validity of this packet before reflecting it.

			// NOTE: The test for "!packetWasFromOurHost" means that we won't reflect RTCP packets that come from other processes on
			// the same host as us.  The reason for this is that the 'packet size' test above is not 100% reliable; some packets
			// that were truly looped back from us might not be detected as such, and this might lead to infinite forwarding/receiving
			// of some packets.  To avoid this possibility, we only reflect RTCP packets that we know for sure originated elsewhere.
			// (Note, though, that if we ever re-enable the code in "Groupsock::multicastSendOnly()", then we could remove the test for
			// "!packetWasFromOurHost".)
			
			fRTCPInterface.sendPacket(pkt, packetSize);
			fHaveJustSentPacket = True;
			fLastPacketSentSize = packetSize;
			
		}

#ifdef DEBUG
		fprintf(stderr, "[%p]saw incoming RTCP packet (from address %s, port %d)\n", this, AddressString(fromAddress).val(), ntohs(fromAddress.sin_port));
		for (unsigned i = 0; i < packetSize; ++i) {
			if (i%4 == 0) fprintf(stderr, " ");
			fprintf(stderr, "%02x", pkt[i]);
		}
		fprintf(stderr, "\n");
#endif
		int totPacketSize = IP_UDP_HDR_SIZE + packetSize;

		// Check the RTCP packet for validity:
		// It must at least contain a header (4 bytes), and this header
		// must be version=2, with no padding bit, and a payload type of
		// SR (200) or RR (201):
		if (packetSize < 4) 
			break;
		
		unsigned rtcpHdr = ntohl(*(u_int32_t*)pkt);
		if ((rtcpHdr & 0xE0FE0000) != (0x80000000 | (RTCP_PT_SR<<16))) {
#ifdef DEBUG
			fprintf(stderr, "rejected bad RTCP packet: header 0x%08x\n", rtcpHdr);
#endif
			break;
		}

		// Process each of the individual RTCP 'subpackets' in (what may be)
		// a compound RTCP packet.
		int typeOfPacket = PACKET_UNKNOWN_TYPE;
		unsigned reportSenderSSRC = 0;
		Boolean packetOK = False;
		while (1) {
			
			unsigned rc = (rtcpHdr>>24)&0x1F;
			unsigned pt = (rtcpHdr>>16)&0xFF;
			unsigned length = 4*(rtcpHdr&0xFFFF); // doesn't count hdr
			ADVANCE(4); // skip over the header
			if (length > packetSize) break;

			// Assume that each RTCP subpacket begins with a 4-byte SSRC:
			if (length < 4) break; length -= 4;
			reportSenderSSRC = ntohl(*(u_int32_t*)pkt); ADVANCE(4);

			Boolean subPacketOK = False;
			
			switch (pt) {
				case RTCP_PT_SR: {
#ifdef DEBUG
							 fprintf(stderr, "SR\n");
#endif
							 if (length < 20) break; length -= 20;

							 // Extract the NTP timestamp, and note this:
							 unsigned NTPmsw = ntohl(*(u_int32_t*)pkt); ADVANCE(4);
							 unsigned NTPlsw = ntohl(*(u_int32_t*)pkt); ADVANCE(4);
							 unsigned rtpTimestamp = ntohl(*(u_int32_t*)pkt); ADVANCE(4);
							 if (fSource != NULL) {
								 RTPReceptionStatsDB& receptionStats
									 = fSource->receptionStatsDB();
								 receptionStats.noteIncomingSR(reportSenderSSRC,
										 NTPmsw, NTPlsw, rtpTimestamp);
							 }
							 ADVANCE(8); // skip over packet count, octet count


							 // If a 'SR handler' was set, call it now:
							 if (fSRHandlerTask != NULL) (*fSRHandlerTask)(fSRHandlerClientData);

							 // The rest of the SR is handled like a RR (so, no "break;" here)
						 }
				
				case RTCP_PT_RR: {
#ifdef DEBUG
							 fprintf(stderr, "RR\n");
#endif
							 unsigned reportBlocksSize = rc*(6*4);
							 if (length < reportBlocksSize) break;
							 length -= reportBlocksSize;

							 if (fSink != NULL) {
								 // Use this information to update stats about our transmissions:
								 RTPTransmissionStatsDB& transmissionStats = fSink->transmissionStatsDB();
								 for (unsigned i = 0; i < rc; ++i) {
									 unsigned senderSSRC = ntohl(*(u_int32_t*)pkt); ADVANCE(4);
									 // We care only about reports about our own transmission, not others'
									 if (senderSSRC == fSink->SSRC()) {
										 unsigned lossStats = ntohl(*(u_int32_t*)pkt); ADVANCE(4);
										 unsigned highestReceived = ntohl(*(u_int32_t*)pkt); ADVANCE(4);
										 unsigned jitter = ntohl(*(u_int32_t*)pkt); ADVANCE(4);
										 unsigned timeLastSR = ntohl(*(u_int32_t*)pkt); ADVANCE(4);
										 unsigned timeSinceLastSR = ntohl(*(u_int32_t*)pkt); ADVANCE(4);
										 transmissionStats.noteIncomingRR(reportSenderSSRC, fromAddress,
												 lossStats,
												 highestReceived, jitter,
												 timeLastSR, timeSinceLastSR);
									 } else {
										 ADVANCE(4*5);
									 }
								 }
							 } else {
								 ADVANCE(reportBlocksSize);
							 }


							 if (pt == RTCP_PT_RR) { // i.e., we didn't fall through from 'SR'
								 // If a 'RR handler' was set, call it now:

								 // Specific RR handler:
								 if (fSpecificRRHandlerTable != NULL) {
									 netAddressBits fromAddr;
									 portNumBits fromPortNum;
									 if (tcpReadStreamSocketNum < 0) {
										 // Normal case: We read the RTCP packet over UDP
										 fromAddr = fromAddress.sin_addr.s_addr;
										 fromPortNum = ntohs(fromAddress.sin_port);
									 } else {
										 // Special case: We read the RTCP packet over TCP (interleaved)
										 // Hack: Use the TCP socket and channel id to look up the handler
										 fromAddr = tcpReadStreamSocketNum;
										 fromPortNum = tcpReadStreamChannelId;
									 }
									 Port fromPort(fromPortNum);
									 RRHandlerRecord* rrHandler
										 = (RRHandlerRecord*)(fSpecificRRHandlerTable->Lookup(fromAddr, (~0), fromPort));
									 if (rrHandler != NULL) {
										 if (rrHandler->rrHandlerTask != NULL) {
											 (*(rrHandler->rrHandlerTask))(rrHandler->rrHandlerClientData);
										 }
									 }
								 }

								 // General RR handler:
								 if (fRRHandlerTask != NULL) (*fRRHandlerTask)(fRRHandlerClientData);
							 }

							 subPacketOK = True;
							 typeOfPacket = PACKET_RTCP_REPORT;
							 break;
						 }
				
				case RTCP_PT_BYE: {
#ifdef DEBUG
							  fprintf(stderr, "BYE\n");
#endif
							  // If a 'BYE handler' was set, arrange for it to be called at the end of this routine.
							  // (Note: We don't call it immediately, in case it happens to cause "this" to be deleted.)
							  if (fByeHandlerTask != NULL
									  && (!fByeHandleActiveParticipantsOnly
										  || (fSource != NULL
											  && fSource->receptionStatsDB().lookup(reportSenderSSRC) != NULL)
										  || (fSink != NULL
											  && fSink->transmissionStatsDB().lookup(reportSenderSSRC) != NULL))) {
								  callByeHandler = True;
							  }

							  // We should really check for & handle >1 SSRCs being present #####

							  subPacketOK = True;
							  typeOfPacket = PACKET_BYE;
							  break;
						  }
						  // Later handle SDES, APP, and compound RTCP packets #####
				default:
#ifdef DEBUG
						  fprintf(stderr, "UNSUPPORTED TYPE(0x%x)\n", pt);
#endif
						  subPacketOK = True;
						  break;
			}
			if (!subPacketOK) break;

			// need to check for (& handle) SSRC collision! #####

#ifdef DEBUG
			fprintf(stderr, "validated RTCP subpacket (type %d): %d, %d, %d, 0x%08x\n", typeOfPacket, rc, pt, length, reportSenderSSRC);
#endif

			// Skip over any remaining bytes in this subpacket:
			ADVANCE(length);

			// Check whether another RTCP 'subpacket' follows:
			if (packetSize == 0) {
				packetOK = True;
				break;
			} else if (packetSize < 4) {
#ifdef DEBUG
				fprintf(stderr, "extraneous %d bytes at end of RTCP packet!\n", packetSize);
#endif
				break;
			}
			rtcpHdr = ntohl(*(u_int32_t*)pkt);
			if ((rtcpHdr & 0xC0000000) != 0x80000000) {
#ifdef DEBUG
				fprintf(stderr, "bad RTCP subpacket: header 0x%08x\n", rtcpHdr);
#endif
				break;
			}
		}

		if (!packetOK) {
#ifdef DEBUG
			fprintf(stderr, "rejected bad RTCP subpacket: header 0x%08x\n", rtcpHdr);
#endif
			break;
		} else {
#ifdef DEBUG
			fprintf(stderr, "validated entire RTCP packet\n");
#endif
		}

		onReceive(typeOfPacket, totPacketSize, reportSenderSSRC);

		// Finally, if we need to call a "BYE" handler, do so now (in case it causes "this" to get deleted):
		if (callByeHandler && fByeHandlerTask != NULL/*sanity check*/) {
			TaskFunc* byeHandler = fByeHandlerTask;
			fByeHandlerTask = NULL; // because we call the handler only once, by default
			(*byeHandler)(fByeHandlerClientData);
		}
	} while (0);
}
Example #7
0
int main(int argc, char ** argv) {
	int listen_port = -1;
	char listen_port_str[8];
	const char * ctrl_socket_path = NULL;

	{
		int opt;
		while ((opt = getopt(argc, argv, "p:hu:")) != EOF) {
			switch (opt) {
			case 'p' :
				listen_port = atoi(optarg);
				break;
			case 'h' :
				fprintf(stderr, "%s [-p port] [-u socket-path]\n", argv[0]);
				fprintf(stderr, "default: -p 9134\n");
				exit(0);
			case 'u' :
				ctrl_socket_path = optarg;
				break;
			}
		}
		argc -= optind;
		argv += optind;
	}

	if (listen_port == -1) {
		listen_port = 9134;
	}
	sprintf(listen_port_str, "%d", listen_port);

	typedef std::vector<fd_ctx> server_sockets_t;
	server_sockets_t server_sockets;
	peer_sockets_t peer_sockets;

	fd_ctx ctrl_socket, ctrl_socket_conn;
	bool ctrl_socket_mode_listen = false;
	bool decay_mode = false;

	ctrl_socket.fd = -1;
	ctrl_socket_conn.fd = -1;

	int sockets_inherited = 0;

	int epoll = epoll_create(1024);
	if (epoll < 0) {
		VPERROR("epoll_create"); exit(1);
	}

	if (ctrl_socket_path) {
		int s = socket(PF_UNIX, SOCK_SEQPACKET, 0);
		if (s < 0) {
			VPERROR("socket(AF_UNIX)");
			exit(1);
		}
		struct sockaddr_un sun;
		sun.sun_family = AF_UNIX;
		strncpy(sun.sun_path, ctrl_socket_path, sizeof(sun.sun_path));

		if (connect(s, (sockaddr *) &sun, sizeof(sun))) {
			if (errno == ECONNREFUSED || errno == ENOENT) {
				if (errno == ECONNREFUSED) {
					if (unlink(ctrl_socket_path) < 0) {
						fprintf(stderr, "unlink(%s): %s\n", ctrl_socket_path, strerror(errno));
						exit(1);
					}
				}
				ctrl_socket_listen(s, ctrl_socket_path);
				ctrl_socket.fd = s;
				poll_in(epoll, &ctrl_socket);
				ctrl_socket_mode_listen = true;
			} else {
				fprintf(stderr, "connect(%s): %s\n", ctrl_socket_path, strerror(errno));
			}
		} else {
			char buf[16];
			ssize_t n = send(s, "unlisten", sizeof("unlisten") - 1, 0);
			if (n < 0) {
				VPERROR("sendmsg");
				exit(1);
			} else if (n == 0) {
				fprintf(stderr, "unexpected EOF\n");
				exit(1);
			}

			// blocking read
			n = recv(s, buf, sizeof(buf), 0);
			if (strncmp(buf, "unlistening", strlen("unlistening")) != 0) {
				fprintf(stderr, "running server reported: ");
				fwrite(buf, n, 1, stderr);
				exit(1);
			}
			ctrl_socket_conn.fd = s;
			poll_in(epoll, &ctrl_socket_conn);
		}
	}

	{
		struct addrinfo hints, * ai_res;
		hints.ai_family   = AF_UNSPEC;
		hints.ai_socktype = SOCK_STREAM;
		hints.ai_protocol = IPPROTO_TCP;
		hints.ai_flags    = AI_PASSIVE;

		int r = getaddrinfo(NULL, listen_port_str, &hints, &ai_res);
		if (r) {
			fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(r));
			exit(1);
		}

		for (struct addrinfo * ai = ai_res; ai; ai = ai->ai_next) {
			int s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
			if (s < 0) {
				VPERROR("socket"); exit(1);
			}
			if (ai->ai_family == AF_INET6) {
				int on = 1;
				if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 
							   (char *)&on, sizeof(on)) == -1) {
					VPERROR("setsockopt(IPV6_ONLY)");
					exit(1);
				}
			}
			{
				int on = 1;
				if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) == -1) {
					VPERROR("setsockopt(REUSEADDR)");
					exit(1);
				}
			}
			if (bind(s, ai->ai_addr, ai->ai_addrlen) < 0) {
				VPERROR("bind"); exit(1);
			}
			if (listen(s, 50) < 0) {
				VPERROR("listen"); exit(1);
			}
			fd_ctx c;
			c.fd = s;
			c.is_server = true;
			c.protocol = ai->ai_protocol;
			char * strp = c.buf;
			int slen  = sizeof(c.buf);
			if (ai->ai_family == AF_INET6) {
				*strp++ = '[';
				slen -= 2;
			}
			get_ip_str(ai->ai_addr, strp, slen);
			if (ai->ai_family == AF_INET6) {
				strcat(c.buf, "]");
			}
			sprintf(c.buf + strlen(c.buf), ":%d", listen_port);
			server_sockets.push_back(c);
		}
		freeaddrinfo(ai_res);
	}

	for (int i = 0; i < server_sockets.size(); ++i) {
		poll_in(epoll, &server_sockets[i]);
	}

	epoll_event epoll_events[32];
	const int epoll_max_events = 32;

	fd_ctx fd_ctx_finder;
	signal(SIGUSR1, sigusr1);
	signal(SIGPIPE, SIG_IGN);

	total_sockets  = server_sockets.size();
	time_t status_time = time(NULL);

	while (total_sockets) {
		if (unlikely(got_sigusr1)) {
			// close listening sockets
			for (int i = 0; i < server_sockets.size(); ++i) {
				fprintf(stderr, "close server %s\n", server_sockets[i].buf);
				if (epoll_ctl(epoll, EPOLL_CTL_DEL, server_sockets[i].fd, NULL) < 0) {
					VPERROR("epoll_ctl");
				}
				close(server_sockets[i].fd);
				--total_sockets;
			}
			got_sigusr1 = false;
		}
		if (unlikely(status_time + 5 < time(NULL))) {
			fprintf(stderr, "%d connections, %d identified peers\n", total_connections - server_sockets.size(), peer_sockets.size());
			status_time = time(NULL);
		}

		int ep_num = epoll_wait(epoll, epoll_events, epoll_max_events, 1000);
		if (unlikely(ep_num < 0)) {
			if (errno == EINTR) continue;
			VPERROR("epoll_wait"); continue;
		}
		bool epoll_restart = false;
		for (int epi = 0; epi < ep_num && ! epoll_restart; ++epi) {
			fd_ctx * ctxp = (fd_ctx *) epoll_events[epi].data.ptr;

			if (unlikely(ctxp == &ctrl_socket)) {
				sockaddr_storage ss;
				socklen_t sl = sizeof(ss);
				
				int nsock = accept(ctxp->fd, (sockaddr *) &ss, &sl);
				if (nsock < 0) {
					VPERROR("accept"); continue;
				}
				epoll_event ev;
				ev.events   = EPOLLIN;
				ev.data.ptr = (void *) &ctrl_socket_conn;
				if (epoll_ctl(epoll, EPOLL_CTL_ADD, nsock, &ev) < 0) {
					VPERROR("epoll_ctl");
					close(nsock);
					continue;
				}

				// we only ever accept one ctrl client
				if (epoll_ctl(epoll, EPOLL_CTL_DEL, ctrl_socket.fd, NULL) < 0) {
					VPERROR("epoll_ctl");
					close(nsock);
					continue;
				}
				ctrl_socket_conn.fd = nsock;
			} else if (unlikely(ctxp == &ctrl_socket_conn)) {
				if (ctrl_socket_mode_listen) {
					char buf[1024];

					int n = read(ctxp->fd, buf, sizeof(buf));
					if (n < 0) {
						if (errno == EINTR || errno == EAGAIN) continue;
						VPERROR("read");
						close(ctxp->fd);
						poll_in(epoll, &ctrl_socket);
					} else if (n == 0) {
						close(ctxp->fd);
						poll_in(epoll, &ctrl_socket);
					} else {
						if (strncmp(buf, "unlisten", sizeof("unlisten") - 1) == 0) {
							for (int i = 0; i < server_sockets.size(); ++i) {
								fprintf(stderr, "close server %s\n", server_sockets[i].buf);
								if (epoll_ctl(epoll, EPOLL_CTL_DEL, server_sockets[i].fd, NULL) < 0) {
									VPERROR("epoll_ctl");
								}
								close(server_sockets[i].fd);
								--total_sockets;
							}
							if (write(ctrl_socket_conn.fd, "unlistening", sizeof("unlistening") - 1) < 0) {
								VPERROR("write");
							} else {
								int nsent = 0;
								
								do {
									nsent = send_fds(ctrl_socket_conn.fd, epoll, peer_sockets.begin(), peer_sockets.end(), &peer_sockets);
									if (nsent) {
										fprintf(stderr, "bulk send: %d\n", nsent);
									}
								} while (nsent && ! peer_sockets.empty());
								epoll_restart = true;
								decay_mode = true;
							}
						}
					}
				} else {
					msghdr msg;
					iovec iov;
					optional_buf<MAX_CONTROL_MESSAGE_CONTROL_SIZE, (MAX_CONTROL_MESSAGE_TOTAL_SIZE > FDCTX_BUFFER_SIZE)> control;
					char * controlp = control.placeholder ?
						ctxp->buf + MAX_CONTROL_MESSAGE_SIZE :
						control.value;
					optional_buf<MAX_CONTROL_MESSAGE_SIZE, (MAX_CONTROL_MESSAGE_SIZE > FDCTX_BUFFER_SIZE)> buf;
					char * bufp = buf.placeholder ?	ctxp->buf : control.value;

					iov.iov_base = bufp;
					iov.iov_len  = MAX_CONTROL_MESSAGE_SIZE;

					msg.msg_name       = NULL;
					msg.msg_namelen    = 0;
					msg.msg_iov        = &iov;
					msg.msg_iovlen     = 1;
					msg.msg_control    = (void *) controlp;
					msg.msg_controllen = MAX_CONTROL_MESSAGE_CONTROL_SIZE;
					msg.msg_flags      = 0;

					int n = recvmsg(ctxp->fd, &msg, 0);
					if (n < 0) {
						VPERROR("recvmsg");
					} else if (n == 0) {
						fprintf(stderr, "unexpected close\n");
						close(ctxp->fd);
					} else {
						if (strncmp((const char *) iov.iov_base, "desc", std::min(4, n)) == 0) {
							cmsghdr * cmp = CMSG_FIRSTHDR(&msg);
							if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_RIGHTS) {
								fprintf(stderr, "malformed control message: wrong type\n");
								exit(1);
							}

							int * uidp = (int *) ((char *) iov.iov_base + 4);
							int * uidpend = (int *) ((char *) iov.iov_base + n);

							int fd_count = 0;
							for (; uidp < uidpend; ++uidp, ++fd_count) {
								int fd = * ((int *) CMSG_DATA(cmp) + fd_count);
								++sockets_inherited;
								++total_sockets;
								fd_ctx * cp = new fd_ctx;
								cp->fd = fd;
								cp->faf_uid = *uidp;
								cp->is_server = false;
								cp->protocol = IPPROTO_TCP;
								cp->buf_len = 0;
								epoll_event ev;
								ev.events = EPOLLIN;
								ev.data.ptr = (void *) cp;
								if (epoll_ctl(epoll, EPOLL_CTL_ADD, cp->fd, &ev) < 0) {
									VPERROR("epoll_ctl");
									--total_sockets;
									close(cp->fd);
									delete cp;
								}
								if (cp->faf_uid != -1) {
									peer_sockets.insert(cp);
								}
							}
						} else if (strncmp((const char *) iov.iov_base, "exit", std::min(4, n)) == 0) {
							close(ctxp->fd);
							int s = socket(PF_UNIX, SOCK_SEQPACKET, 0);
							if (s < 0) {
								VPERROR("socket(PF_UNIX)");
							} else {
								ctrl_socket_listen(s, ctrl_socket_path);
								ctrl_socket.fd = s;
								poll_in(epoll, &ctrl_socket);
								ctrl_socket_mode_listen = true;
							}
							fprintf(stderr, "%d sockets inherited from the dead\n", sockets_inherited);
						}
					}
				}
			} else if (unlikely(ctxp->is_server && ctxp->protocol == IPPROTO_TCP)) {
				sockaddr_storage saddr;
				socklen_t saddrlen = sizeof(saddr);
				int nsock = accept(ctxp->fd, (sockaddr *) &saddr, &saddrlen);
				if (nsock < 0) {
					VPERROR("accept");
				} else {
					++total_sockets;
					fd_ctx * cp = new fd_ctx;
					cp->fd = nsock;
					cp->faf_uid = -1;
					cp->is_server = false;
					cp->protocol = IPPROTO_TCP;
					cp->buf_len = 0;

					epoll_event ev;
					ev.events = EPOLLIN;
					ev.data.ptr = (void *) cp;
					if (epoll_ctl(epoll, EPOLL_CTL_ADD, nsock, &ev) < 0) {
						VPERROR("epoll_ctl");
						--total_sockets;
						close(nsock);
						delete cp;
					}
				}
			} else {
				if (unlikely(decay_mode && ctxp->buf_len == 0)) {
					fprintf(stderr, "single send\n");
					send_fd(ctrl_socket_conn.fd, epoll, ctxp);
					if (ctxp->faf_uid != -1) {
						peer_sockets.erase(ctxp);
					}
					continue; // -> next epoll result
				}

				int n = read(ctxp->fd, ctxp->buf + ctxp->buf_len, PEER_CTX_BUF_SIZE - ctxp->buf_len);
				if (unlikely(n < 0)) {
					if (errno != ECONNRESET && errno != EAGAIN && errno != EINTR) {
						VPERROR("read");
					}
					continue;
				} else if (unlikely(n == 0)) {
					close(ctxp->fd);
					--total_sockets;
					if (ctxp->faf_uid != -1) {
						peer_sockets.erase(ctxp);
					}
					ctxp->remove_myself_from_peer_caches();
					--ctxp->refcount;
					if (ctxp->refcount == 0) {
						delete ctxp;
					} else {
						ctxp->faf_uid = -1;
					}
				} else {
					ctxp->buf_len += n;
					char * buf_head = ctxp->buf;
					bool postprocess = true;

					while (buf_head < ctxp->buf + ctxp->buf_len) {
						proxy_msg_header * h = (proxy_msg_header *) buf_head;
						const int buf_len = ctxp->buf + ctxp->buf_len - buf_head;
						const int in_msg_size = ntohl(h->size);

						if (buf_len < 4) {
							break;
						}
						
						if (unlikely(buf_len > PEER_CTX_BUF_SIZE)) {
							// message to big
							if (epoll_ctl(epoll, EPOLL_CTL_DEL, ctxp->fd, NULL) < 0) {
								VPERROR("epoll_ctl");
							}
							close(ctxp->fd);
							--total_sockets;
							if (ctxp->faf_uid != -1) {
								peer_sockets.erase(ctxp);
							}
							ctxp->remove_myself_from_peer_caches();
							--ctxp->refcount;
							if (ctxp->refcount == 0) {
								delete ctxp;
							} else {
								ctxp->faf_uid = -1;
							}
							postprocess = false;
							break;
						}

						if (in_msg_size + 4 > buf_len) {
							break;
						}

						if (unlikely(ctxp->faf_uid == -1)) {
							proxy_msg_header_set_uid * hu = (proxy_msg_header_set_uid *) h;
							ctxp->faf_uid = ntohs(hu->uid);
							peer_sockets.insert(ctxp);

							buf_head += in_msg_size + 4;
							continue; // -> next message from this fd_ctx
						}

						// in decay mode we always drop, because we expect our
						// caches and refcounts to be inconsistent
						// we can decay without bookkeeping if we never send any packets
						// out (== we never expect a context to exists unless epoll still
						// knows about it)
						if (! decay_mode) {
							int uid = ntohs(h->destuid);

							fd_ctx * peer = ctxp->peers.find(uid);

							if (unlikely(! peer)) {
								fd_ctx_finder.faf_uid = uid;
								peer_sockets_t::iterator iter = peer_sockets.find(&fd_ctx_finder);
								if (iter != peer_sockets.end()) {
									peer = *iter;
									ctxp->peers.add(peer);
								} else {
									buf_head += in_msg_size + 4;
									continue;
								}
							}
							
							int in_port = ntohs(h->port);
							proxy_msg_header_to_peer * hout = (proxy_msg_header_to_peer *) (buf_head + OUT_HEADER_OFFSET_ADJ);
							hout->port = htons(in_port);
							const int out_size = in_msg_size - OUT_HEADER_OFFSET_ADJ;
							hout->size = htonl(out_size);
							
							{
								int n = write(peer->fd, (char *) hout, out_size + 4);
								if (unlikely(n < 0)) {
									if (errno != ECONNRESET && errno != EPIPE) {
										VPERROR("write");
									}
								} else if (unlikely(n != out_size + 4)) {
									fprintf(stderr, "short write (%d of %d\n", n, out_size + 4);
								}
							}
						}
						buf_head += in_msg_size + 4;
					}
					if (likely(postprocess)) {
						int new_buflen = ctxp->buf + ctxp->buf_len - buf_head;

						if (unlikely(new_buflen && ctxp->buf != buf_head)) {
							for (char * p = ctxp->buf; buf_head < ctxp->buf + ctxp->buf_len; ++p, ++buf_head) {
								*p = *buf_head;
							}
						}
						ctxp->buf_len = new_buflen;
					}
					// we want to get rid of clients as soon as possible and
					// dont wait for them to send the next message to trigger it
					if (unlikely(decay_mode && ctxp->buf_len == 0)) {
						send_fd(ctrl_socket_conn.fd, epoll, ctxp);
						if (ctxp->faf_uid != -1) {
							peer_sockets.erase(ctxp);
						}
					}
				}
			}
		}
	}
	if (decay_mode && ctrl_socket_path) {
		close(ctrl_socket.fd);
		unlink(ctrl_socket_path);
		if (write(ctrl_socket_conn.fd, "exit", strlen("exit")) < 0) {
			VPERROR("send");
		}
	}
	fprintf(stderr, "exit due to %d sockets left to serve\n", total_sockets);
	exit(0);
}
static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
			       const char **dptr, unsigned int *datalen)
{
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
	unsigned int coff, matchoff, matchlen;
	enum sip_header_types hdr;
	union nf_inet_addr addr;
	__be16 port;
	int request, in_header;

	/* Basic rules: requests and responses. */
	if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
		if (ct_sip_parse_request(ct, *dptr, *datalen,
					 &matchoff, &matchlen,
					 &addr, &port) > 0 &&
		    !map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
			      &addr, port))
			return NF_DROP;
		request = 1;
	} else
		request = 0;

	if (nf_ct_protonum(ct) == IPPROTO_TCP)
		hdr = SIP_HDR_VIA_TCP;
	else
		hdr = SIP_HDR_VIA_UDP;

	/* Translate topmost Via header and parameters */
	if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
				    hdr, NULL, &matchoff, &matchlen,
				    &addr, &port) > 0) {
		unsigned int olen, matchend, poff, plen, buflen, n;
		char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];

		/* We're only interested in headers related to this
		 * connection */
		if (request) {
			if (addr.ip != ct->tuplehash[dir].tuple.src.u3.ip ||
			    port != ct->tuplehash[dir].tuple.src.u.udp.port)
				goto next;
		} else {
			if (addr.ip != ct->tuplehash[dir].tuple.dst.u3.ip ||
			    port != ct->tuplehash[dir].tuple.dst.u.udp.port)
				goto next;
		}

		olen = *datalen;
		if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
			      &addr, port))
			return NF_DROP;

		matchend = matchoff + matchlen + *datalen - olen;

		/* The maddr= parameter (RFC 2361) specifies where to send
		 * the reply. */
		if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
					       "maddr=", &poff, &plen,
					       &addr) > 0 &&
		    addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
		    addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
			buflen = sprintf(buffer, "%pI4",
					&ct->tuplehash[!dir].tuple.dst.u3.ip);
			if (!mangle_packet(skb, dataoff, dptr, datalen,
					   poff, plen, buffer, buflen))
				return NF_DROP;
		}

		/* The received= parameter (RFC 2361) contains the address
		 * from which the server received the request. */
		if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
					       "received=", &poff, &plen,
					       &addr) > 0 &&
		    addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
		    addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
			buflen = sprintf(buffer, "%pI4",
					&ct->tuplehash[!dir].tuple.src.u3.ip);
			if (!mangle_packet(skb, dataoff, dptr, datalen,
					   poff, plen, buffer, buflen))
				return NF_DROP;
		}

		/* The rport= parameter (RFC 3581) contains the port number
		 * from which the server received the request. */
		if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
						 "rport=", &poff, &plen,
						 &n) > 0 &&
		    htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
		    htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
			__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
			buflen = sprintf(buffer, "%u", ntohs(p));
			if (!mangle_packet(skb, dataoff, dptr, datalen,
					   poff, plen, buffer, buflen))
				return NF_DROP;
		}
	}

next:
	/* Translate Contact headers */
	coff = 0;
	in_header = 0;
	while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen,
				       SIP_HDR_CONTACT, &in_header,
				       &matchoff, &matchlen,
				       &addr, &port) > 0) {
		if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
			      &addr, port))
			return NF_DROP;
	}

	if (!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_FROM) ||
	    !map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO))
		return NF_DROP;

	return NF_ACCEPT;
}
static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
				      const char **dptr, unsigned int *datalen,
				      struct nf_conntrack_expect *exp,
				      unsigned int matchoff,
				      unsigned int matchlen)
{
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
	__be32 newip;
	u_int16_t port;
	char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
	unsigned int buflen;

	/* Connection will come from reply */
	if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip)
		newip = exp->tuple.dst.u3.ip;
	else
		newip = ct->tuplehash[!dir].tuple.dst.u3.ip;

	/* If the signalling port matches the connection's source port in the
	 * original direction, try to use the destination port in the opposite
	 * direction. */
	if (exp->tuple.dst.u.udp.port ==
	    ct->tuplehash[dir].tuple.src.u.udp.port)
		port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
	else
		port = ntohs(exp->tuple.dst.u.udp.port);

	exp->saved_ip = exp->tuple.dst.u3.ip;
	exp->tuple.dst.u3.ip = newip;
	exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
	exp->dir = !dir;
	exp->expectfn = ip_nat_sip_expected;

	for (; port != 0; port++) {
		int ret;

		exp->tuple.dst.u.udp.port = htons(port);
		ret = nf_ct_expect_related(exp);
		if (ret == 0)
			break;
		else if (ret != -EBUSY) {
			port = 0;
			break;
		}
	}

	if (port == 0)
		return NF_DROP;

	if (exp->tuple.dst.u3.ip != exp->saved_ip ||
	    exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
		buflen = sprintf(buffer, "%pI4:%u", &newip, port);
		if (!mangle_packet(skb, dataoff, dptr, datalen,
				   matchoff, matchlen, buffer, buflen))
			goto err;
	}
	return NF_ACCEPT;

err:
	nf_ct_unexpect_related(exp);
	return NF_DROP;
}
Example #10
0
File: xbee.c Project: Angeldude/pd
/* Accept data from an XBee module & build into valid XBEE
 *  packets
 */
void xbee_in(xbee_t *xbee, const void *buf, uint8_t len)
{
    uint8_t *data = (uint8_t *)buf;


    while(len) {
        switch(xbee->in.bytes_rcvd) {
            case 0:
                while (*data != XBEE_PKT_START) {
                    if (!--len)
                        return;
                    data++;
                }

                xbee->in.hdr_data[xbee->in.bytes_rcvd++] = *data++;
                if (!--len)
                    return;

                /* Fall thru */

            case 1:
              xbee->in.hdr_data[xbee->in.bytes_rcvd++] = *data++;
                if (!--len)
                    return;

                /* Fall thru */

            case 2:
              xbee->in.hdr_data[xbee->in.bytes_rcvd++] = *data++;

                /* Got enough to get packet length */

                xbee->in.bytes_left = ntohs(((xbee_pkt_hdr_t *)xbee->in.hdr_data)->len);

                if (xbee->in.bytes_left > XBEE_MAX_DATA_LEN
                    || ((xbee->in.packet 
                              = xbee_alloc_pkt_mem(XBEE_RECV, xbee->in.bytes_left + 4)) == NULL)
                )
                {
                    xbee->in.bytes_left = 0;
                    xbee_rx_err(xbee);
                    continue;
                }

                xbee->in.bytes_left++; /* Extra for crc (alloc_pkt already accounts for it) */

                memcpy(&(xbee->in.packet->hdr), &(xbee->in.hdr_data),
                         sizeof(xbee->in.hdr_data));

                if (!--len)
                    return;

                /* Fall thru */

            default:
                while (xbee->in.bytes_left--) {
                    ((uint8_t *)xbee->in.packet)[xbee->in.bytes_rcvd++] = *data++;
                    if (!--len && xbee->in.bytes_left)
                        return;
                }
        }

        if (xbee_crc(xbee->in.packet) 
                     != ((uint8_t *)xbee->in.packet)[xbee->in.bytes_rcvd - 1])
        {
            xbee->in.bytes_rcvd = 0;
            xbee_rx_crc_err(xbee);
            continue;
        }

        if (xbee_recv_pkt(xbee, xbee->in.packet, xbee->in.bytes_rcvd)) {
            xbee_free_pkt_mem(xbee->in.packet);
            xbee_rx_dropped(xbee);
        }

        xbee->in.bytes_rcvd = 0;
    }
}
Example #11
0
size_t
ldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
                            const size_t len,
                            const ldns_algorithm alg)
{
	/* for DSA keys */
	uint8_t t;
	
	/* for RSA keys */
	uint16_t exp;
	uint16_t int16;
	
	switch ((ldns_signing_algorithm)alg) {
	case LDNS_SIGN_DSA:
	case LDNS_SIGN_DSA_NSEC3:
		if (len > 0) {
			t = keydata[0];
			return (64 + t*8)*8;
		} else {
			return 0;
		}
		break;
	case LDNS_SIGN_RSAMD5:
	case LDNS_SIGN_RSASHA1:
	case LDNS_SIGN_RSASHA1_NSEC3:
#ifdef USE_SHA2
	case LDNS_SIGN_RSASHA256:
	case LDNS_SIGN_RSASHA512:
#endif
		if (len > 0) {
			if (keydata[0] == 0) {
				/* big exponent */
				if (len > 3) {
					memmove(&int16, keydata + 1, 2);
					exp = ntohs(int16);
					return (len - exp - 3)*8;
				} else {
					return 0;
				}
			} else {
				exp = keydata[0];
				return (len-exp-1)*8;
			}
		} else {
			return 0;
		}
		break;
#ifdef USE_GOST
	case LDNS_SIGN_ECC_GOST:
		return 512;
#endif
#ifdef USE_ECDSA
        case LDNS_SIGN_ECDSAP256SHA256:
                return 256;
        case LDNS_SIGN_ECDSAP384SHA384:
                return 384;
#endif
	case LDNS_SIGN_HMACMD5:
		return len;
	default:
		return 0;
	}
}
Example #12
0
Tcl_Channel
Tcl_OpenTcpServer(
    Tcl_Interp *interp,		/* For error reporting - may be NULL. */
    int port,			/* Port number to open. */
    const char *myHost,		/* Name of local host. */
    Tcl_TcpAcceptProc *acceptProc,
				/* Callback for accepting connections from new
				 * clients. */
    ClientData acceptProcData)	/* Data for the callback. */
{
    int status = 0, sock = -1, reuseaddr = 1, chosenport = 0;
    struct addrinfo *addrlist = NULL, *addrPtr;	/* socket address */
    TcpState *statePtr = NULL;
    char channelName[SOCK_CHAN_LENGTH];
    const char *errorMsg = NULL;
    TcpFdList *fds = NULL, *newfds;

    /*
     * Try to record and return the most meaningful error message, i.e. the
     * one from the first socket that went the farthest before it failed.
     */

    enum { LOOKUP, SOCKET, BIND, LISTEN } howfar = LOOKUP;
    int my_errno = 0;

    if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) {
	my_errno = errno;
	goto error;
    }

    for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) {
	sock = socket(addrPtr->ai_family, addrPtr->ai_socktype,
                addrPtr->ai_protocol);
	if (sock == -1) {
	    if (howfar < SOCKET) {
		howfar = SOCKET;
		my_errno = errno;
	    }
	    continue;
	}
	
	/*
	 * Set the close-on-exec flag so that the socket will not get
	 * inherited by child processes.
	 */
	
	fcntl(sock, F_SETFD, FD_CLOEXEC);
	
	/*
	 * Set kernel space buffering
	 */
	
	TclSockMinimumBuffers(INT2PTR(sock), SOCKET_BUFSIZE);
	
	/*
	 * Set up to reuse server addresses automatically and bind to the
	 * specified port.
	 */
	
	(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 
		(char *) &reuseaddr, sizeof(reuseaddr));
	
        /*
         * Make sure we use the same port number when opening two server
         * sockets for IPv4 and IPv6 on a random port.
         *
         * As sockaddr_in6 uses the same offset and size for the port member
         * as sockaddr_in, we can handle both through the IPv4 API.
         */

	if (port == 0 && chosenport != 0) {
	    ((struct sockaddr_in *) addrPtr->ai_addr)->sin_port =
                    htons(chosenport);
	}

#ifdef IPV6_V6ONLY
	/* Missing on: Solaris 2.8 */
        if (addrPtr->ai_family == AF_INET6) {
            int v6only = 1;

            (void) setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
                    &v6only, sizeof(v6only));
        }
#endif /* IPV6_V6ONLY */

	status = bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen);
        if (status == -1) {
	    if (howfar < BIND) {
		howfar = BIND;
		my_errno = errno;
	    }       
            close(sock);
            continue;
        }
        if (port == 0 && chosenport == 0) {
            address sockname;
            socklen_t namelen = sizeof(sockname);

            /*
             * Synchronize port numbers when binding to port 0 of multiple
             * addresses.
             */

            if (getsockname(sock, &sockname.sa, &namelen) >= 0) {
                chosenport = ntohs(sockname.sa4.sin_port);
            }
        }
        status = listen(sock, SOMAXCONN);
        if (status < 0) {
	    if (howfar < LISTEN) {
		howfar = LISTEN;
		my_errno = errno;
	    }
            close(sock);
            continue;
        }
        if (statePtr == NULL) {
            /*
             * Allocate a new TcpState for this socket.
             */
            
            statePtr = ckalloc(sizeof(TcpState));
            memset(statePtr, 0, sizeof(TcpState));
            statePtr->acceptProc = acceptProc;
            statePtr->acceptProcData = acceptProcData;
            sprintf(channelName, SOCK_TEMPLATE, (long) statePtr);
            newfds = &statePtr->fds;
        } else {
            newfds = ckalloc(sizeof(TcpFdList));
            memset(newfds, (int) 0, sizeof(TcpFdList));
            fds->next = newfds;
        }
        newfds->fd = sock;
        newfds->statePtr = statePtr;
        fds = newfds;
	
        /*
         * Set up the callback mechanism for accepting connections from new
         * clients.
         */
        
        Tcl_CreateFileHandler(sock, TCL_READABLE, TcpAccept, fds);
    }

  error:
    if (addrlist != NULL) {
	freeaddrinfo(addrlist);
    }
    if (statePtr != NULL) {
	statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
		statePtr, 0);
	return statePtr->channel;
    }
    if (interp != NULL) {
        Tcl_Obj *errorObj = Tcl_NewStringObj("couldn't open socket: ", -1);

	if (errorMsg == NULL) {
            errno = my_errno;
            Tcl_AppendToObj(errorObj, Tcl_PosixError(interp), -1);
        } else {
	    Tcl_AppendToObj(errorObj, errorMsg, -1);
	}
        Tcl_SetObjResult(interp, errorObj);
    }
    if (sock != -1) {
	close(sock);
    }
    return NULL;
}
Example #13
0
int
__loadctype(const char *name)
{
  FILE *fp;
  char id[sizeof(_CTYPE_ID) - 1];
  u_int32_t i, len;
  unsigned short *new_ctype = NULL;
  unsigned char *new_toupper = NULL, *new_tolower = NULL;

  _DIAGASSERT(name != NULL);

  if ((fp = fopen(name, "r")) == NULL)
    return 0;

  if (fread(id, sizeof(id), 1, fp) != 1)
    goto bad;

  if (memcmp(id, _CTYPE_ID, sizeof(id)) != 0)
    goto bad;

  if (fread(&i, sizeof(u_int32_t), 1, fp) != 1)
    goto bad;

  if ((i = ntohl(i)) != _CTYPE_REV)
    goto bad;

  if (fread(&len, sizeof(u_int32_t), 1, fp) != 1)
    goto bad;

  if ((len = ntohl(len)) != _CTYPE_NUM_CHARS)
    goto bad;

  if ((new_ctype = malloc(sizeof(UINT16) * (1 + len))) == NULL)
    goto bad;

  new_ctype[0] = 0;
  if (fread(&new_ctype[1], sizeof(UINT16), len, fp) != len)
    goto bad;

  if ((new_toupper = malloc(sizeof(UINT8) * (1 + len))) == NULL)
    goto bad;

  new_toupper[0] = (UINT8)EOF;
  if (fread(&new_toupper[1], sizeof(UINT8), len, fp) != len)
    goto bad;

  if ((new_tolower = malloc(sizeof(UINT8) * (1 + len))) == NULL)
    goto bad;

  new_tolower[0] = (UINT8)EOF;
  if (fread(&new_tolower[1], sizeof(UINT8), len, fp) != len)
    goto bad;

#if BYTE_ORDER == LITTLE_ENDIAN
  for (i = 1; i <= len; i++) {
    new_ctype[i] = ntohs(new_ctype[i]);
  }
#endif

  (void) fclose(fp);
  if (_cClass != _C_CharClassTable)
    free(__UNCONST(_cClass));
  _cClass = new_ctype;
  if (_uConvT != _C_ToUpperTable)
    free(__UNCONST(_uConvT));
  _uConvT = new_toupper;
  if (_lConvT != _C_ToLowerTable)
    free(__UNCONST(_lConvT));
  _lConvT = new_tolower;

  return 1;
bad:
  free(new_tolower);
  free(new_toupper);
  free(new_ctype);
  (void) fclose(fp);
  return 0;
}
Example #14
0
// track a tcp stream.  returns the difference between this packet's
// SEQ and the expected next SEQ.
int
IpConnTrack_track_stream(IpConnTrack *self, IpConn *conn, 
			 IpConnTcpQueue *queue, 
			 struct netpkt *pkt, 
			 int buffer_stream) {
    netpkt_tcp *tcp;
    netpkt_udp *udp;
    tcp_seq_t seq;
    char *dst, *src;
    int len, diff=0;
    
    do {
	tcp = pkt->pkt_tcp;
	udp = pkt->pkt_udp;
	src = pkt->pkt_msg;
	len = pkt->pkt_len;
	diff = 0;
	
	if( tcp ) {
	    if( tcp_ack(tcp) ) {
		queue->ack = ntohl(tcp->ack_seq);
	    }
	    queue->win = ntohs(tcp->window);

	    seq = ntohl(tcp->seq);

	    if( !queue->seq_ok ) {
		queue->seq_syn = seq;
		queue->seq =  seq;
		queue->seq_ok = 1;
		if( tcp_syn(tcp) ) {
		    queue->seq++;
		}
		else {
		    conn->conn_pkt_flags |= CONN_PKT_TCP_MISSED_SYN;
		}
	    }
	
	    diff = tcp_seq_diff(seq, queue->seq);

	    if( diff > 1 ) {
		// ignore packets (far) in the future
		conn->conn_pkt_flags |= CONN_PKT_TCP_FUTURE_SEQ;
		break;
	    }

	    src += -diff;
	    len -= -diff;
	    if( len <= 0 ) {
		// ignore past packets
		break;
	    }
	    queue->seq += len;
	}
	else if( udp ) {
	}
	
	if( buffer_stream ) {
	    dst = (char*)array_add(&queue->buf, len);
	    assertb(dst);
	    memcpy(dst, src, len);
	}
    } while(0);
    
    return diff;
}
Example #15
0
int main(int argc, char **argv) {
  int opt;
  int epoll_fd, serial_fd, e131_fd;
  uint16_t universe = 0x0001;
  char *device = NULL;
  speed_t baud_rate = B0;
  struct epoll_event epoll_events[MAX_EPOLL_EVENTS];
  int nfds, i;
  e131_packet_t e131_packet;
  e131_error_t e131_error;
  uint8_t last_seq_number = 0x00;

  // program options
  while ((opt = getopt(argc, argv, "hu:d:b:")) != -1) {
    switch (opt) {
      case 'h':
        show_usage(argv[0]);
        exit(EXIT_SUCCESS);
      case 'u':
        sscanf(optarg, "%" SCNu16, &universe);
        if (universe < 0x0001 || universe > 0xf9ff) {
          fprintf(stderr, "error: universe must be between 1-63999\n");
          exit(EXIT_FAILURE);
        }
        break;
      case 'd':
        device = optarg;
        break;
      case 'b':
        baud_rate = parse_baud_rate(optarg);
        if (baud_rate == B0) {
          fprintf(stderr, "error: invalid baud rate: %s\n", optarg);
          exit(EXIT_FAILURE);
        }
        break;
      default:
        fprintf(stderr, "Try '%s -h' for more information.\n", argv[0]);
        exit(EXIT_FAILURE);
    }
  }
  if (device == NULL || baud_rate == B0) {
    fprintf(stderr, "error: you must specify serial device and baud rate\n");
    show_usage(argv[0]);
    exit(EXIT_FAILURE);
  }

  // create an epoll file descriptor
  if ((epoll_fd = epoll_create(1)) < 0)
    err(EXIT_FAILURE, "epoll_create1");

  // open serial device and initialise
  if ((serial_fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
    err(EXIT_FAILURE, "serial device open");
  init_serial(serial_fd, baud_rate);
  epoll_add_fd(epoll_fd, serial_fd);
  fprintf(stderr, "serial device '%s' opened\n", device);

  // open E1.31 socket and join multicast group for the universe
  if ((e131_fd = e131_socket()) < 0)
    err(EXIT_FAILURE, "e131_socket");
  if (e131_bind(e131_fd, E131_DEFAULT_PORT) < 0)
    err(EXIT_FAILURE, "e131_bind");
  if (e131_multicast_join(e131_fd, universe) < 0)
    err(EXIT_FAILURE, "e131_multicast_join");
  epoll_add_fd(epoll_fd, e131_fd);
  fprintf(stderr, "E1.31 multicast server listening on port %d\n", E131_DEFAULT_PORT);

  // bridge E1.31 data to AdaLight
  fprintf(stderr, "bridging E1.31 (sACN) to AdaLight, use CTRL+C to stop\n");
  for (;;) {
    // wait for an epoll event
    if ((nfds = epoll_wait(epoll_fd, epoll_events, MAX_EPOLL_EVENTS, -1)) < 0)
      err(EXIT_FAILURE, "epoll_wait");

    // check received epoll events
    for (i=0; i<nfds; i++) {
      if (epoll_events[i].data.fd == serial_fd) { // serial port data received
        tcflush(serial_fd, TCIFLUSH);
        continue;
      }
      if (epoll_events[i].data.fd == e131_fd) { // E1.31 network data received
        if (e131_recv(e131_fd, &e131_packet) < 0)
          err(EXIT_FAILURE, "e131_recv");
        if ((e131_error = e131_pkt_validate(&e131_packet)) != E131_ERR_NONE) {
          fprintf(stderr, "e131_pkt_validate: %s\n", e131_strerror(e131_error));
          continue;
        }
        if (e131_pkt_discard(&e131_packet, last_seq_number)) {
          fprintf(stderr, "warning: out of order E1.31 packet received\n");
          last_seq_number = e131_packet.frame.seq_number;
          continue;
        }
        send_adalight(serial_fd, e131_packet.dmp.prop_val + 1, \
          ntohs(e131_packet.dmp.prop_val_cnt) - 1);
        last_seq_number = e131_packet.frame.seq_number;
      }
    }
  }

  // finished
  close(e131_fd);
  close(serial_fd);
  close(epoll_fd);
  exit(EXIT_SUCCESS);
}
/* So, this packet has hit the connection tracking matching code.
   Mangle it, and change the expectation to match the new version. */
static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
				     const char **dptr, unsigned int *datalen,
				     struct nf_conntrack_expect *rtp_exp,
				     struct nf_conntrack_expect *rtcp_exp,
				     unsigned int mediaoff,
				     unsigned int medialen,
				     union nf_inet_addr *rtp_addr)
{
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
	u_int16_t port;

	/* Connection will come from reply */
	if (ct->tuplehash[dir].tuple.src.u3.ip ==
	    ct->tuplehash[!dir].tuple.dst.u3.ip)
		rtp_addr->ip = rtp_exp->tuple.dst.u3.ip;
	else
		rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip;

	rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
	rtp_exp->tuple.dst.u3.ip = rtp_addr->ip;
	rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
	rtp_exp->dir = !dir;
	rtp_exp->expectfn = ip_nat_sip_expected;

	rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
	rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip;
	rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
	rtcp_exp->dir = !dir;
	rtcp_exp->expectfn = ip_nat_sip_expected;

	/* Try to get same pair of ports: if not, try to change them. */
	for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
	     port != 0; port += 2) {
		int ret;

		rtp_exp->tuple.dst.u.udp.port = htons(port);
		ret = nf_ct_expect_related(rtp_exp);
		if (ret == -EBUSY)
			continue;
		else if (ret < 0) {
			port = 0;
			break;
		}
		rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
		ret = nf_ct_expect_related(rtcp_exp);
		if (ret == 0)
			break;
		else if (ret == -EBUSY) {
			nf_ct_unexpect_related(rtp_exp);
			continue;
		} else if (ret < 0) {
			nf_ct_unexpect_related(rtp_exp);
			port = 0;
			break;
		}
	}

	if (port == 0)
		goto err1;

	/* Update media port. */
	if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
	    !ip_nat_sdp_port(skb, dataoff, dptr, datalen,
			     mediaoff, medialen, port))
		goto err2;

	return NF_ACCEPT;

err2:
	nf_ct_unexpect_related(rtp_exp);
	nf_ct_unexpect_related(rtcp_exp);
err1:
	return NF_DROP;
}
Example #17
0
static void setup_transport(char *recipient)
{
	static int transport_is_setup = 0;
	int default_port;

	if (transport_is_setup) return;
	transport_is_setup = 1;

	if (strncmp(recipient, "http://", 7) == 0) {
		/*
		 * Send messages via http. This requires e.g. a CGI on the webserver to
		 * receive the POST we do here.
		 */
		default_port = 80;

		if (proxysetting == NULL) proxysetting = getenv("http_proxy");
		if (proxysetting) {
			char *p;

			xymonproxyhost = strdup(proxysetting);
			if (strncmp(xymonproxyhost, "http://", 7) == 0) xymonproxyhost += strlen("http://");
 
			p = strchr(xymonproxyhost, ':');
			if (p) {
				*p = '\0';
				p++;
				xymonproxyport = atoi(p);
			}
			else {
				xymonproxyport = 8080;
			}
		}
	}
	else {
		/* 
		 * Non-HTTP transport - lookup portnumber in both XYMONDPORT env.
		 * and the "xymond" entry from /etc/services.
		 */
		default_port = 1984;

		if (xgetenv("XYMONDPORT")) xymondportnumber = atoi(xgetenv("XYMONDPORT"));
	
	
		/* Next is /etc/services "bbd" entry */
		if ((xymondportnumber <= 0) || (xymondportnumber > 65535)) {
			struct servent *svcinfo;

			svcinfo = getservbyname("bbd", NULL);
			if (svcinfo) xymondportnumber = ntohs(svcinfo->s_port);
		}
	}

	/* Last resort: The default value */
	if ((xymondportnumber <= 0) || (xymondportnumber > 65535)) {
		xymondportnumber = default_port;
	}

	dbgprintf("Transport setup is:\n");
	dbgprintf("xymondportnumber = %d\n", xymondportnumber),
	dbgprintf("xymonproxyhost = %s\n", (xymonproxyhost ? xymonproxyhost : "NONE"));
	dbgprintf("xymonproxyport = %d\n", xymonproxyport);
}
Example #18
0
void BaseTCPServer::ListenNewConnections() {
	SOCKET tmpsock;
	struct sockaddr_in	from;
	struct in_addr	in;
	unsigned int	fromlen;
	unsigned short	port;

	from.sin_family = AF_INET;
	fromlen = sizeof(from);
	LockMutex lock(&MSock);
#ifndef DARWIN // Corysia - On OSX, 0 is a valid fd.
	if (!sock)
		return;
#else
	if (sock == -1) return;
#endif

	// Check for pending connects
#ifdef _WINDOWS
	unsigned long nonblocking = 1;
	while ((tmpsock = accept(sock, (struct sockaddr*) &from, (int *) &fromlen)) != INVALID_SOCKET) {
		ioctlsocket (tmpsock, FIONBIO, &nonblocking);
#else
#ifdef __CYGWIN__
	while ((tmpsock = accept(sock, (struct sockaddr *) &from, (int *) &fromlen)) != INVALID_SOCKET) {
#else
	while ((tmpsock = accept(sock, (struct sockaddr*) &from, &fromlen)) != INVALID_SOCKET) {
#endif
		fcntl(tmpsock, F_SETFL, O_NONBLOCK);
#endif
		int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
		setsockopt(tmpsock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
		port = from.sin_port;
		in.s_addr = from.sin_addr.s_addr;

		// New TCP connection, this must consume the socket.
		CreateNewConnection(GetNextID(), tmpsock, in.s_addr, ntohs(from.sin_port));
	}
}

bool BaseTCPServer::Open(uint16 in_port, char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	LockMutex lock(&MSock);
	if (sock != 0) {
		if (errbuf)
			snprintf(errbuf, TCPServer_ErrorBufferSize, "Listening socket already open");
		return false;
	}
	if (in_port != 0) {
		pPort = in_port;
	}

#ifdef _WINDOWS
	SOCKADDR_IN address;
	unsigned long nonblocking = 1;
#else
	struct sockaddr_in address;
#endif
	int reuse_addr = 1;

//	Setup internet address information.
//	This is used with the bind() call
	memset((char *) &address, 0, sizeof(address));
	address.sin_family = AF_INET;
	address.sin_port = htons(pPort);
	address.sin_addr.s_addr = htonl(INADDR_ANY);

//	Setting up TCP port for new TCP connections
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock == INVALID_SOCKET) {
		if (errbuf)
			snprintf(errbuf, TCPServer_ErrorBufferSize, "socket(): INVALID_SOCKET");
		return false;
	}

// Quag: dont think following is good stuff for TCP, good for UDP
// Mis: SO_REUSEADDR shouldn't be a problem for tcp--allows you to restart
// without waiting for conns in TIME_WAIT to die
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse_addr, sizeof(reuse_addr));


	if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) {
#ifdef _WINDOWS
		closesocket(sock);
#else
		close(sock);
#endif
		sock = 0;
		if (errbuf)
			sprintf(errbuf, "bind(): <0");
		return false;
	}

	int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
	setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
#ifdef _WINDOWS
	ioctlsocket (sock, FIONBIO, &nonblocking);
#else
	fcntl(sock, F_SETFL, O_NONBLOCK);
#endif

	if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
#ifdef _WINDOWS
		closesocket(sock);
		if (errbuf)
			snprintf(errbuf, TCPServer_ErrorBufferSize, "listen() failed, Error: %d", WSAGetLastError());
#else
		close(sock);
		if (errbuf)
			snprintf(errbuf, TCPServer_ErrorBufferSize, "listen() failed, Error: %s", strerror(errno));
#endif
		sock = 0;
		return false;
	}

	return true;
}

void BaseTCPServer::Close() {
	StopLoopAndWait();

	LockMutex lock(&MSock);
	if (sock) {
#ifdef _WINDOWS
		closesocket(sock);
#else
		close(sock);
#endif
	}
	sock = 0;
}

bool BaseTCPServer::IsOpen() {
	MSock.lock();
	bool ret = (bool) (sock != 0);
	MSock.unlock();
	return ret;
}
Example #19
0
void ipoque_search_aimini(struct ipoque_detection_module_struct *ipoque_struct)
{
    struct ipoque_packet_struct *packet = &ipoque_struct->packet;
    struct ipoque_flow_struct *flow = ipoque_struct->flow;
    //    struct ipoque_id_struct         *src=ipoque_struct->src;
    //    struct ipoque_id_struct         *dst=ipoque_struct->dst;


    IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "search aimini.\n");

    if (packet->udp != NULL) {
        if (flow->l4.udp.aimini_stage == 0) {
            if (packet->payload_packet_len == 64 && ntohs(get_u16(packet->payload, 0)) == 0x010b) {
                flow->l4.udp.aimini_stage = 1;
                IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 1.\n");
                return;
            }
            if (packet->payload_packet_len == 136
                    && (ntohs(get_u16(packet->payload, 0)) == 0x01c9 || ntohs(get_u16(packet->payload, 0)) == 0x0165)) {
                flow->l4.udp.aimini_stage = 4;
                IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 4.\n");
                return;
            }
            if (packet->payload_packet_len == 88 && ntohs(get_u16(packet->payload, 0)) == 0x0101) {
                flow->l4.udp.aimini_stage = 7;
                IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 7.\n");
                return;
            }
            if (packet->payload_packet_len == 104 && ntohs(get_u16(packet->payload, 0)) == 0x0102) {
                flow->l4.udp.aimini_stage = 10;
                IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 10.\n");
                return;
            }
            if (packet->payload_packet_len == 32 && ntohs(get_u16(packet->payload, 0)) == 0x01ca) {
                flow->l4.udp.aimini_stage = 13;
                IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 13.\n");
                return;
            }
            if (packet->payload_packet_len == 16 && ntohs(get_u16(packet->payload, 0)) == 0x010c) {
                flow->l4.udp.aimini_stage = 16;
                IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 16.\n");
                return;
            }
        }
        /* first packet chronology: (len, value): (64, 0x010b), (>100, 0x0115), (16, 0x010c || 64, 0x010b || 88, 0x0115),
         * (16, 0x010c || 64, 0x010b || >100, 0x0115)
         */
        if (flow->l4.udp.aimini_stage == 1 && packet->payload_packet_len > 100
                && ntohs(get_u16(packet->payload, 0)) == 0x0115) {
            flow->l4.udp.aimini_stage = 2;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 2.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 2 &&
                ((packet->payload_packet_len == 16 && get_u16(packet->payload, 0) == htons(0x010c)) ||
                 (packet->payload_packet_len == 64 && get_u16(packet->payload, 0) == htons(0x010b)) ||
                 (packet->payload_packet_len == 88 && get_u16(packet->payload, 0) == ntohs(0x0115)))) {
            flow->l4.udp.aimini_stage = 3;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 3.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 3
                && ((packet->payload_packet_len == 16 && ntohs(get_u16(packet->payload, 0)) == 0x010c)
                    || (packet->payload_packet_len == 64 && ntohs(get_u16(packet->payload, 0)) == 0x010b)
                    || (packet->payload_packet_len > 100 && ntohs(get_u16(packet->payload, 0)) == 0x0115))) {
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "found aimini (64, 0x010b), (>300, 0x0115), "
                    "(16, 0x010c || 64, 0x010b), (16, 0x010c || 64, 0x010b || >100, 0x0115).\n");
            ipoque_int_aimini_add_connection(ipoque_struct, IPOQUE_REAL_PROTOCOL);
            return;
        }

        /* second packet chronology: (len, value): (136, 0x01c9), (136, 0x01c9),(136, 0x01c9),(136, 0x01c9 || 32, 0x01ca) */

        if (flow->l4.udp.aimini_stage == 4 && packet->payload_packet_len == 136
                && (ntohs(get_u16(packet->payload, 0)) == 0x01c9 || ntohs(get_u16(packet->payload, 0)) == 0x0165)) {
            flow->l4.udp.aimini_stage = 5;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 5.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 5 && (packet->payload_packet_len == 136
                                               && (ntohs(get_u16(packet->payload, 0)) == 0x01c9
                                                       || ntohs(get_u16(packet->payload, 0)) == 0x0165))) {
            flow->l4.udp.aimini_stage = 6;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 6.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 6 && ((packet->payload_packet_len == 136
                                                && ((ntohs(get_u16(packet->payload, 0)) == 0x0165)
                                                        || ntohs(get_u16(packet->payload, 0)) == 0x01c9))
                                               || (packet->payload_packet_len == 32
                                                       && ntohs(get_u16(packet->payload, 0)) == 0x01ca))) {
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG,
                    "found aimini (136, 0x01c9), (136, 0x01c9)," "(136, 0x01c9),(136, 0x01c9 || 32, 0x01ca).\n");
            ipoque_int_aimini_add_connection(ipoque_struct, IPOQUE_REAL_PROTOCOL);
            return;
        }

        /* third packet chronology: (len, value): (88, 0x0101), (88, 0x0101),(88, 0x0101),(88, 0x0101) */

        if (flow->l4.udp.aimini_stage == 7 && packet->payload_packet_len == 88
                && ntohs(get_u16(packet->payload, 0)) == 0x0101) {
            flow->l4.udp.aimini_stage = 8;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 8.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 8
                && (packet->payload_packet_len == 88 && ntohs(get_u16(packet->payload, 0)) == 0x0101)) {
            flow->l4.udp.aimini_stage = 9;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 9.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 9
                && (packet->payload_packet_len == 88 && ntohs(get_u16(packet->payload, 0)) == 0x0101)) {
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG,
                    "found aimini (88, 0x0101), (88, 0x0101)," "(88, 0x0101),(88, 0x0101).\n");
            ipoque_int_aimini_add_connection(ipoque_struct, IPOQUE_REAL_PROTOCOL);
            return;
        }

        /* fourth packet chronology: (len, value): (104, 0x0102), (104, 0x0102), (104, 0x0102), (104, 0x0102) */

        if (flow->l4.udp.aimini_stage == 10 && packet->payload_packet_len == 104
                && ntohs(get_u16(packet->payload, 0)) == 0x0102) {
            flow->l4.udp.aimini_stage = 11;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 11.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 11
                && (packet->payload_packet_len == 104 && ntohs(get_u16(packet->payload, 0)) == 0x0102)) {
            flow->l4.udp.aimini_stage = 12;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 12.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 12
                && ((packet->payload_packet_len == 104 && ntohs(get_u16(packet->payload, 0)) == 0x0102)
                    || (packet->payload_packet_len == 32 && ntohs(get_u16(packet->payload, 0)) == 0x01ca))) {
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG,
                    "found aimini (104, 0x0102), (104, 0x0102), " "(104, 0x0102), (104, 0x0102).\n");
            ipoque_int_aimini_add_connection(ipoque_struct, IPOQUE_REAL_PROTOCOL);
            return;
        }

        /* fifth packet chronology (len, value): (32,0x01ca), (32,0x01ca), (32,0x01ca), ((136, 0x0166) || (32,0x01ca)) */

        if (flow->l4.udp.aimini_stage == 13 && packet->payload_packet_len == 32
                && ntohs(get_u16(packet->payload, 0)) == 0x01ca) {
            flow->l4.udp.aimini_stage = 14;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 14.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 14
                && ((packet->payload_packet_len == 32 && ntohs(get_u16(packet->payload, 0)) == 0x01ca)
                    || (packet->payload_packet_len == 136 && ntohs(get_u16(packet->payload, 0)) == 0x0166))) {
            flow->l4.udp.aimini_stage = 15;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 15.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 15
                && ((packet->payload_packet_len == 136 && ntohs(get_u16(packet->payload, 0)) == 0x0166)
                    || (packet->payload_packet_len == 32 && ntohs(get_u16(packet->payload, 0)) == 0x01ca))) {
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG,
                    "found aimini (32,0x01ca), (32,0x01ca), (32,0x01ca), ((136, 0x0166)||(32,0x01ca)).\n");
            ipoque_int_aimini_add_connection(ipoque_struct, IPOQUE_REAL_PROTOCOL);
            return;
        }

        /* sixth packet chronology (len, value): (16, 0x010c), (16, 0x010c), (16, 0x010c), (16, 0x010c) */

        if (flow->l4.udp.aimini_stage == 16 && packet->payload_packet_len == 16
                && ntohs(get_u16(packet->payload, 0)) == 0x010c) {
            flow->l4.udp.aimini_stage = 17;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 17.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 17
                && (packet->payload_packet_len == 16 && ntohs(get_u16(packet->payload, 0)) == 0x010c)) {
            flow->l4.udp.aimini_stage = 18;
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "stage = 18.\n");
            return;
        }
        if (flow->l4.udp.aimini_stage == 18
                && (packet->payload_packet_len == 16 && ntohs(get_u16(packet->payload, 0)) == 0x010c)) {
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG,
                    "found aimini (16, 0x010c), (16, 0x010c), (16, 0x010c), (16, 0x010c).\n");
            ipoque_int_aimini_add_connection(ipoque_struct, IPOQUE_REAL_PROTOCOL);
            return;
        }
    } else if (packet->tcp != NULL) {
        if ((packet->payload_packet_len > IPQ_STATICSTRING_LEN("GET /player/") &&
                (memcmp(packet->payload, "GET /player/", IPQ_STATICSTRING_LEN("GET /player/")) == 0)) ||
                (packet->payload_packet_len > IPQ_STATICSTRING_LEN("GET /play/?fid=") &&
                 (memcmp(packet->payload, "GET /play/?fid=", IPQ_STATICSTRING_LEN("GET /play/?fid=")) == 0))) {
            IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "HTTP packet detected.\n");
            ipq_parse_packet_line_info(ipoque_struct);
            if (packet->host_line.ptr != NULL && packet->host_line.len > 11
                    && (memcmp(&packet->host_line.ptr[packet->host_line.len - 11], ".aimini.net", 11) == 0)) {
                IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "AIMINI HTTP traffic detected.\n");
                ipoque_int_aimini_add_connection(ipoque_struct, IPOQUE_CORRELATED_PROTOCOL);
                return;
            }
        }
        if (packet->payload_packet_len > 100) {
            if (memcmp(packet->payload, "GET /", IPQ_STATICSTRING_LEN("GET /")) == 0) {
                if (memcmp(&packet->payload[IPQ_STATICSTRING_LEN("GET /")], "play/",
                           IPQ_STATICSTRING_LEN("play/")) == 0 ||
                        memcmp(&packet->payload[IPQ_STATICSTRING_LEN("GET /")], "download/",
                               IPQ_STATICSTRING_LEN("download/")) == 0) {
                    ipq_parse_packet_line_info(ipoque_struct);
                    if (is_special_aimini_host(packet->host_line) == 1) {
                        IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG,
                                "AIMINI HTTP traffic detected.\n");
                        ipoque_int_aimini_add_connection(ipoque_struct, IPOQUE_CORRELATED_PROTOCOL);
                        return;
                    }
                }
            } else if (memcmp(packet->payload, "POST /", IPQ_STATICSTRING_LEN("POST /")) == 0) {
                if (memcmp(&packet->payload[IPQ_STATICSTRING_LEN("POST /")], "upload/",
                           IPQ_STATICSTRING_LEN("upload/")) == 0) {
                    ipq_parse_packet_line_info(ipoque_struct);
                    if (is_special_aimini_host(packet->host_line) == 1) {
                        IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG,
                                "AIMINI HTTP traffic detected.\n");
                        ipoque_int_aimini_add_connection(ipoque_struct, IPOQUE_CORRELATED_PROTOCOL);
                        return;
                    }
                }
            }
        }
    }

    IPQ_LOG(IPOQUE_PROTOCOL_AIMINI, ipoque_struct, IPQ_LOG_DEBUG, "exclude aimini.\n");
    IPOQUE_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, IPOQUE_PROTOCOL_AIMINI);

}
Example #20
0
File: nicdrv.c Project: mheden/SOEM
/** Non blocking receive frame function. Uses RX buffer and index to combine
 * read frame with transmitted frame. To compensate for received frames that
 * are out-of-order all frames are stored in their respective indexed buffer.
 * If a frame was placed in the buffer previously, the function retreives it
 * from that buffer index without calling ec_recvpkt. If the requested index
 * is not already in the buffer it calls ec_recvpkt to fetch it. There are
 * three options now, 1 no frame read, so exit. 2 frame read but other
 * than requested index, store in buffer and exit. 3 frame read with matching
 * index, store in buffer, set completed flag in buffer status and exit.
 *
 * @param[in] port        = port context struct
 * @param[in] idx         = requested index of frame
 * @param[in] stacknumber = 0=primary 1=secondary stack
 * @return Workcounter if a frame is found with corresponding index, otherwise
 * EC_NOFRAME or EC_OTHERFRAME.
 */
int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
{
   uint16  l;
   int     rval;
   int     idxf;
   ec_etherheadert *ehp;
   ec_comt *ecp;
   ec_stackT *stack;
   ec_bufT *rxbuf;

   if (!stacknumber)
   {
      stack = &(port->stack);
   }
   else
   {
      stack = &(port->redport->stack);
   }
   rval = EC_NOFRAME;
   rxbuf = &(*stack->rxbuf)[idx];
   /* check if requested index is already in buffer ? */
   if ((idx < EC_MAXBUF) && ((*stack->rxbufstat)[idx] == EC_BUF_RCVD))
   {
      l = (*rxbuf)[0] + ((uint16)((*rxbuf)[1] & 0x0f) << 8);
      /* return WKC */
      rval = ((*rxbuf)[l] + ((uint16)(*rxbuf)[l + 1] << 8));
      /* mark as completed */
      (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
   }
   else
   {
      pthread_mutex_lock(&(port->rx_mutex));
      /* non blocking call to retrieve frame from socket */
      if (ecx_recvpkt(port, stacknumber))
      {
         rval = EC_OTHERFRAME;
         ehp =(ec_etherheadert*)(stack->tempbuf);
         /* check if it is an EtherCAT frame */
         if (ehp->etype == htons(ETH_P_ECAT))
         {
            ecp =(ec_comt*)(&(*stack->tempbuf)[ETH_HEADERSIZE]);
            l = etohs(ecp->elength) & 0x0fff;
            idxf = ecp->index;
            /* found index equals reqested index ? */
            if (idxf == idx)
            {
               /* yes, put it in the buffer array (strip ethernet header) */
               memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idx] - ETH_HEADERSIZE);
               /* return WKC */
               rval = ((*rxbuf)[l] + ((uint16)((*rxbuf)[l + 1]) << 8));
               /* mark as completed */
               (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
               /* store MAC source word 1 for redundant routing info */
               (*stack->rxsa)[idx] = ntohs(ehp->sa1);
            }
            else
            {
               /* check if index exist? */
               if (idxf < EC_MAXBUF)
               {
                  rxbuf = &(*stack->rxbuf)[idxf];
                  /* put it in the buffer array (strip ethernet header) */
                  memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idxf] - ETH_HEADERSIZE);
                  /* mark as received */
                  (*stack->rxbufstat)[idxf] = EC_BUF_RCVD;
                  (*stack->rxsa)[idxf] = ntohs(ehp->sa1);
               }
               else
               {
                  /* strange things happend */
               }
            }
         }
      }
      pthread_mutex_unlock( &(port->rx_mutex) );

   }

   /* WKC if mathing frame found */
   return rval;
}
/* parses:
 *     tcp|udp|unix:host_name:port
 *     tcp|udp|unix:host_name
 *     host_name:port
 *     host_name
 * 
 *
 *     where host_name=string, ipv4 address, [ipv6 address],
 *         unix socket path (starts with '/')
 */
struct id_list* parse_listen_id(char* l, int len, enum socket_protos def)
{
	char* p;
	enum socket_protos proto;
	char* name;
	char* port_str;
	int port;
	int err;
	struct servent* se;
	char* s;
	struct id_list* id;
	
	s=pkg_malloc((len+1)*sizeof(char));
	if (s==0){
		LOG(L_ERR, "ERROR:parse_listen_id: out of memory\n");
		goto error;
	}
	memcpy(s, l, len);
	s[len]=0; /* null terminate */
	
	/* duplicate */
	proto=UNKNOWN_SOCK;
	port=0;
	name=0;
	port_str=0;
	p=s;
	
	if ((*p)=='[') goto ipv6;
	/* find proto or name */
	for (; *p; p++){
		if (*p==':'){
			*p=0;
			if (strcasecmp("tcp", s)==0){
				proto=TCP_SOCK;
				goto find_host;
			}else if (strcasecmp("udp", s)==0){
				proto=UDP_SOCK;
				goto find_host;
			}else if (strcasecmp("unixd", s)==0){
				proto=UNIXD_SOCK;
				goto find_host;
			}else if ((strcasecmp("unix", s)==0)||(strcasecmp("unixs", s)==0)){
				proto=UNIXS_SOCK;
				goto find_host;
#ifdef USE_FIFO
			}else if (strcasecmp("fifo", s)==0){
				proto=FIFO_SOCK;
				goto find_host;
#endif
			}else{
				proto=UNKNOWN_SOCK;
				/* this might be the host */
				name=s;
				goto find_port;
			}
		}
	}
	name=s;
	goto end; /* only name found */
find_host:
	p++;
	if (*p=='[') goto ipv6;
	name=p;
	for (; *p; p++){
		if ((*p)==':'){
			*p=0;
			goto find_port;
		}
	}
	goto end; /* nothing after name */
ipv6:
	name=p;
	p++;
	for(;*p;p++){
		if(*p==']'){
			if(*(p+1)==':'){
				p++; *p=0;
				goto find_port;
			}else if (*(p+1)==0) goto end;
		}else{
			goto error;
		}
	}
	
find_port:
	p++;
	port_str=(*p)?p:0;
	
end:
	/* fix all the stuff */
	if (name==0) goto error;
	if (proto==UNKNOWN_SOCK){
		/* try to guess */
		if (port_str){
			switch(def){
				case TCP_SOCK:
				case UDP_SOCK:
					proto=def;
					break;
				default:
					proto=UDP_SOCK;
					DBG("guess:%s is a tcp socket\n", name);
			}
		}else if (name && strchr(name, '/')){
			switch(def){
				case TCP_SOCK:
				case UDP_SOCK:
					DBG("guess:%s is a unix socket\n", name);
					proto=UNIXS_SOCK;
					break;
				default:
					/* def is filename based => use default */
					proto=def;
			}
		}else{
			/* using default */
			proto=def;
		}
	}
	if (port_str){
		port=str2s(port_str, strlen(port_str), &err);
		if (err){
			/* try getservbyname */
			se=getservbyname(port_str, 
					(proto==TCP_SOCK)?"tcp":(proto==UDP_SOCK)?"udp":0);
			if (se) port=ntohs(se->s_port);
			else goto error;
		}
	}else{
		/* no port, check if the hostname is a port 
		 * (e.g. tcp:3012 == tcp:*:3012 */
		if (proto==TCP_SOCK|| proto==UDP_SOCK){
			port=str2s(name, strlen(name), &err);
			if (err){
				port=0;
			}else{
				name="*"; /* inaddr any  */
			}
		}
	}
	id=pkg_malloc(sizeof(struct id_list));
	if (id==0){
		LOG(L_ERR, "ERROR:parse_listen_id: out of memory\n");
		goto error;
	}
	id->name=name;
	id->proto=proto;
	id->data_proto=P_BINRPC;
	id->port=port;
	id->buf=s;
	id->next=0;
	return id;
error:
	if (s) pkg_free(s);
	return 0;
}
Example #22
0
int rc_send_server (rc_handle *rh, SEND_DATA *data, char *msg)
{
	int             sockfd;
	struct sockaddr_in sinlocal;
	struct sockaddr_in sinremote;
	AUTH_HDR       *auth, *recv_auth;
	uint32_t           auth_ipaddr, nas_ipaddr;
	char           *server_name;	/* Name of server to query */
	socklen_t       salen;
	int             result = 0;
	int             total_length;
	int             length;
	int             retry_max;
	size_t			secretlen;
	char            secret[MAX_SECRET_LENGTH + 1];
	unsigned char   vector[AUTH_VECTOR_LEN];
	// uint16_t for alignment
	uint16_t		recv_buffer[BUFFER_LEN / sizeof(uint16_t)];
	uint16_t		send_buffer[BUFFER_LEN / sizeof(uint16_t)];
	int		retries;
	VALUE_PAIR 	*vp;
	struct pollfd	pfd;
	double		start_time, timeout;

	memset(send_buffer, 0, BUFFER_LEN);
	server_name = data->server;
	if (server_name == NULL || server_name[0] == '\0')
		return ERROR_RC;

	if ((vp = rc_avpair_get(data->send_pairs, PW_SERVICE_TYPE, 0)) && \
	    (vp->lvalue == PW_ADMINISTRATIVE))
	{
		strcpy(secret, MGMT_POLL_SECRET);
		if ((auth_ipaddr = rc_get_ipaddr(server_name)) == 0)
			return ERROR_RC;
	}
	else
	{
		if(data->secret != NULL)
		{
			strncpy(secret, data->secret, MAX_SECRET_LENGTH);
		}
		/*
		else
		{
		*/
		if (rc_find_server (rh, server_name, &auth_ipaddr, secret) != 0)
		{
			rc_log(LOG_ERR, "rc_send_server: unable to find server: %s", server_name);
			return ERROR_RC;
		}
		/*}*/
	}

	DEBUG(LOG_ERR, "DEBUG: rc_send_server: creating socket to: %s", server_name);

	sockfd = socket (AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0)
	{
		memset (secret, '\0', sizeof (secret));
		rc_log(LOG_ERR, "rc_send_server: socket: %s", strerror(errno));
		return ERROR_RC;
	}

	memset((char *)&sinlocal, '\0', sizeof(sinlocal));
	sinlocal.sin_family = AF_INET;
	sinlocal.sin_addr.s_addr = htonl(rc_own_bind_ipaddress(rh));
	sinlocal.sin_port = htons((unsigned short) 0);
	if (bind(sockfd, SA(&sinlocal), sizeof(sinlocal)) < 0)
	{
		close (sockfd);
		memset (secret, '\0', sizeof (secret));
		rc_log(LOG_ERR, "rc_send_server: bind: %s: %s", server_name, strerror(errno));
		return ERROR_RC;
	}

	retry_max = data->retries;	/* Max. numbers to try for reply */
	retries = 0;			/* Init retry cnt for blocking call */

	memset ((char *)&sinremote, '\0', sizeof(sinremote));
	sinremote.sin_family = AF_INET;
	sinremote.sin_addr.s_addr = htonl (auth_ipaddr);
	sinremote.sin_port = htons ((unsigned short) data->svc_port);

	/*
	 * Fill in NAS-IP-Address (if needed)
	 */
	if (rc_avpair_get(data->send_pairs, PW_NAS_IP_ADDRESS, 0) == NULL) {
		if (sinlocal.sin_addr.s_addr == htonl(INADDR_ANY)) {
			if (rc_get_srcaddr(SA(&sinlocal), SA(&sinremote)) != 0) {
				close (sockfd);
				memset (secret, '\0', sizeof (secret));
				return ERROR_RC;
			}
		}
		nas_ipaddr = ntohl(sinlocal.sin_addr.s_addr);
		rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IP_ADDRESS,
		    &nas_ipaddr, 0, 0);
	}

	/* Build a request */
	auth = (AUTH_HDR *) send_buffer;
	auth->code = data->code;
	auth->id = data->seq_nbr;

	if (data->code == PW_ACCOUNTING_REQUEST)
	{
		total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;

		auth->length = htons ((unsigned short) total_length);

		memset((char *) auth->vector, 0, AUTH_VECTOR_LEN);
		secretlen = strlen (secret);
		memcpy ((char *) auth + total_length, secret, secretlen);
		rc_md5_calc (vector, (unsigned char *) auth, total_length + secretlen);
		memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
	}
	else
	{
		rc_random_vector (vector);
		memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);

		total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;

		auth->length = htons ((unsigned short) total_length);
	}

	DEBUG(LOG_ERR, "DEBUG: local %s : 0, remote %s : %u\n", 
		inet_ntoa(sinlocal.sin_addr),
		inet_ntoa(sinremote.sin_addr), data->svc_port);

	for (;;)
	{
		sendto (sockfd, (char *) auth, (unsigned int) total_length, (int) 0,
			SA(&sinremote), sizeof (struct sockaddr_in));

		pfd.fd = sockfd;
		pfd.events = POLLIN;
		pfd.revents = 0;
		start_time = rc_getctime();
		for (timeout = data->timeout; timeout > 0;
		    timeout -= rc_getctime() - start_time) {
			result = poll(&pfd, 1, timeout * 1000);
			if (result != -1 || errno != EINTR)
				break;
		}
		if (result == -1)
		{
			rc_log(LOG_ERR, "rc_send_server: poll: %s", strerror(errno));
			memset (secret, '\0', sizeof (secret));
			close (sockfd);
			return ERROR_RC;
		}
		if (result == 1 && (pfd.revents & POLLIN) != 0)
			break;

		/*
		 * Timed out waiting for response.  Retry "retry_max" times
		 * before giving up.  If retry_max = 0, don't retry at all.
		 */
		if (retries++ >= retry_max)
		{
			rc_log(LOG_ERR,
				"rc_send_server: no reply from RADIUS server %s:%u, %s",
				 rc_ip_hostname (auth_ipaddr), data->svc_port, inet_ntoa(sinremote.sin_addr));
			close (sockfd);
			memset (secret, '\0', sizeof (secret));
			return TIMEOUT_RC;
		}
	}
	salen = sizeof(sinremote);
	length = recvfrom (sockfd, (char *) recv_buffer,
			   (int) sizeof (recv_buffer),
			   (int) 0, SA(&sinremote), &salen);

	if (length <= 0)
	{
		rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: %s", server_name,\
			 data->svc_port, strerror(errno));
		close (sockfd);
		memset (secret, '\0', sizeof (secret));
		return ERROR_RC;
	}

	recv_auth = (AUTH_HDR *)recv_buffer;

	if (length < AUTH_HDR_LEN || length < ntohs(recv_auth->length)) {
		rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: reply is too short",
		    server_name, data->svc_port);
		close(sockfd);
		memset(secret, '\0', sizeof(secret));
		return ERROR_RC;
	}

	result = rc_check_reply (recv_auth, BUFFER_LEN, secret, vector, data->seq_nbr);

	length = ntohs(recv_auth->length)  - AUTH_HDR_LEN;
	if (length > 0) {
		data->receive_pairs = rc_avpair_gen(rh, NULL, recv_auth->data,
		    length, 0);
	} else {
		data->receive_pairs = NULL;
	}

	close (sockfd);
	memset (secret, '\0', sizeof (secret));

	if (result != OK_RC) return result;

	*msg = '\0';
	vp = data->receive_pairs;
	while (vp)
	{
		if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE, 0)))
		{
			strcat(msg, vp->strvalue);
			strcat(msg, "\n");
			vp = vp->next;
		}
	}

	if ((recv_auth->code == PW_ACCESS_ACCEPT) ||
		(recv_auth->code == PW_PASSWORD_ACK) ||
		(recv_auth->code == PW_ACCOUNTING_RESPONSE))
	{
		result = OK_RC;
	}
	else if ((recv_auth->code == PW_ACCESS_REJECT) ||
		(recv_auth->code == PW_PASSWORD_REJECT))
	{
		result = REJECT_RC;
	}
	else
	{
		result = BADRESP_RC;
	}

	return result;
}
Example #23
0
static int __ncptcp_rcv_proc(struct ncp_server *server)
{
	/* We have to check the result, so store the complete header */
	while (1) {
		int result;
		struct ncp_request_reply *req;
		int datalen;
		int type;

		while (server->rcv.len) {
			result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
			if (result == -EAGAIN) {
				return 0;
			}
			if (result <= 0) {
				req = server->rcv.creq;
				if (req) {
					__ncp_abort_request(server, req, -EIO);
				} else {
					__ncptcp_abort(server);
				}
				if (result < 0) {
					printk(KERN_ERR "ncpfs: tcp: error in recvmsg: %d\n", result);
				} else {
					DPRINTK(KERN_ERR "ncpfs: tcp: EOF\n");
				}
				return -EIO;
			}
			if (server->rcv.ptr) {
				server->rcv.ptr += result;
			}
			server->rcv.len -= result;
		}
		switch (server->rcv.state) {
			case 0:
				if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
					printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
					__ncptcp_abort(server);
					return -EIO;
				}
				datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
				if (datalen < 10) {
					printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
					__ncptcp_abort(server);
					return -EIO;
				}
#ifdef CONFIG_NCPFS_PACKET_SIGNING				
				if (server->sign_active) {
					if (datalen < 18) {
						printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
						__ncptcp_abort(server);
						return -EIO;
					}
					server->rcv.buf.len = datalen - 8;
					server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
					server->rcv.len = 8;
					server->rcv.state = 4;
					break;
				}
#endif				
				type = ntohs(server->rcv.buf.type);
#ifdef CONFIG_NCPFS_PACKET_SIGNING				
cont:;				
#endif
				if (type != NCP_REPLY) {
					if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
						*(__u16*)(server->unexpected_packet.data) = htons(type);
						server->unexpected_packet.len = datalen - 8;

						server->rcv.state = 5;
						server->rcv.ptr = server->unexpected_packet.data + 2;
						server->rcv.len = datalen - 10;
						break;
					}					
					DPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", type);
skipdata2:;
					server->rcv.state = 2;
skipdata:;
					server->rcv.ptr = NULL;
					server->rcv.len = datalen - 10;
					break;
				}
				req = server->rcv.creq;
				if (!req) {
					DPRINTK(KERN_ERR "ncpfs: Reply without appropriate request\n");
					goto skipdata2;
				}
				if (datalen > req->datalen + 8) {
					printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
					server->rcv.state = 3;
					goto skipdata;
				}
				req->datalen = datalen - 8;
				((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
				server->rcv.ptr = server->rxbuf + 2;
				server->rcv.len = datalen - 10;
				server->rcv.state = 1;
				break;
#ifdef CONFIG_NCPFS_PACKET_SIGNING				
			case 4:
				datalen = server->rcv.buf.len;
				type = ntohs(server->rcv.buf.type2);
				goto cont;
#endif
			case 1:
				req = server->rcv.creq;
				if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
					if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
						printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
						__ncp_abort_request(server, req, -EIO);
						return -EIO;
					}
					if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
						printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
						__ncp_abort_request(server, req, -EIO);
						return -EIO;
					}
				}
#ifdef CONFIG_NCPFS_PACKET_SIGNING				
				if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
					if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
						printk(KERN_ERR "ncpfs: tcp: Signature violation\n");
						__ncp_abort_request(server, req, -EIO);
						return -EIO;
					}
				}
#endif				
				ncp_finish_request(server, req, req->datalen);
			nextreq:;
				__ncp_next_request(server);
			case 2:
			next:;
				server->rcv.ptr = (unsigned char*)&server->rcv.buf;
				server->rcv.len = 10;
				server->rcv.state = 0;
				break;
			case 3:
				ncp_finish_request(server, server->rcv.creq, -EIO);
				goto nextreq;
			case 5:
				info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
				goto next;
		}
	}
}
Example #24
0
static int rc_check_reply (AUTH_HDR *auth, int bufferlen, char *secret, unsigned char *vector, uint8_t seq_nbr)
{
	int             secretlen;
	int             totallen;
	unsigned char   calc_digest[AUTH_VECTOR_LEN];
	unsigned char   reply_digest[AUTH_VECTOR_LEN];
#ifdef DIGEST_DEBUG
	uint8_t		*ptr;
#endif

	totallen = ntohs (auth->length);
	secretlen = (int)strlen (secret);

	/* Do sanity checks on packet length */
	if ((totallen < 20) || (totallen > 4096))
	{
		rc_log(LOG_ERR, "rc_check_reply: received RADIUS server response with invalid length");
		return BADRESP_RC;
	}

	/* Verify buffer space, should never trigger with current buffer size and check above */
	if ((totallen + secretlen) > bufferlen)
	{
		rc_log(LOG_ERR, "rc_check_reply: not enough buffer space to verify RADIUS server response");
		return BADRESP_RC;
	}

	/* Verify that id (seq. number) matches what we sent */
	if (auth->id != seq_nbr)
	{
		rc_log(LOG_ERR, "rc_check_reply: received non-matching id in RADIUS server response");
		return BADRESP_RC;
	}

	/* Verify the reply digest */
	memcpy ((char *) reply_digest, (char *) auth->vector, AUTH_VECTOR_LEN);
	memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
	memcpy ((char *) auth + totallen, secret, secretlen);
#ifdef DIGEST_DEBUG
        rc_log(LOG_ERR, "Calculating digest on:");
        for (ptr = (u_char *)auth; ptr < ((u_char *)auth) + totallen + secretlen; ptr += 32) {
                char buf[65];
                int i;

                buf[0] = '\0';
                for (i = 0; i < 32; i++) {
                        if (ptr + i >= ((u_char *)auth) + totallen + secretlen)
                                break;
                        sprintf(buf + i * 2, "%.2X", ptr[i]);
                }
                rc_log(LOG_ERR, "  %s", buf);
        }
#endif
	rc_md5_calc (calc_digest, (unsigned char *) auth, totallen + secretlen);
#ifdef DIGEST_DEBUG
	rc_log(LOG_ERR, "Calculated digest is:");
        for (ptr = (u_char *)calc_digest; ptr < ((u_char *)calc_digest) + 16; ptr += 32) {
                char buf[65];
                int i;

                buf[0] = '\0';
                for (i = 0; i < 32; i++) {
                        if (ptr + i >= ((u_char *)calc_digest) + 16)
                                break;
                        sprintf(buf + i * 2, "%.2X", ptr[i]);
                }
                rc_log(LOG_ERR, "  %s", buf);
        }
	rc_log(LOG_ERR, "Reply digest is:");
        for (ptr = (u_char *)reply_digest; ptr < ((u_char *)reply_digest) + 16; ptr += 32) {
                char buf[65];
                int i;

                buf[0] = '\0';
                for (i = 0; i < 32; i++) {
                        if (ptr + i >= ((u_char *)reply_digest) + 16)
                                break;
                        sprintf(buf + i * 2, "%.2X", ptr[i]);
                }
                rc_log(LOG_ERR, "  %s", buf);
        }
#endif

	if (memcmp ((char *) reply_digest, (char *) calc_digest,
		    AUTH_VECTOR_LEN) != 0)
	{
#ifdef RADIUS_116
		/* the original Livingston radiusd v1.16 seems to have
		   a bug in digest calculation with accounting requests,
		   authentication request are ok. i looked at the code
		   but couldn't find any bugs. any help to get this
		   kludge out are welcome. preferably i want to
		   reproduce the calculation bug here to be compatible
		   to stock Livingston radiusd v1.16.	-lf, 03/14/96
		 */
		if (auth->code == PW_ACCOUNTING_RESPONSE)
			return OK_RC;
#endif
		rc_log(LOG_ERR, "rc_check_reply: received invalid reply digest from RADIUS server");
		return BADRESP_RC;
	}

	return OK_RC;

}
Example #25
0
__private_extern__ void
inpcb_get_ports_used(uint32_t ifindex, int protocol, uint32_t flags,
    bitstr_t *bitfield, struct inpcbinfo *pcbinfo)
{
	struct inpcb *inp;
	struct socket *so;
	inp_gen_t gencnt;
	bool iswildcard, wildcardok, nowakeok;
	bool recvanyifonly, extbgidleok;
	bool activeonly;

	wildcardok = ((flags & INPCB_GET_PORTS_USED_WILDCARDOK) != 0);
	nowakeok = ((flags & INPCB_GET_PORTS_USED_NOWAKEUPOK) != 0);
	recvanyifonly = ((flags & INPCB_GET_PORTS_USED_RECVANYIFONLY) != 0);
	extbgidleok = ((flags & INPCB_GET_PORTS_USED_EXTBGIDLEONLY) != 0);
	activeonly = ((flags & INPCB_GET_PORTS_USED_ACTIVEONLY) != 0);

	lck_rw_lock_shared(pcbinfo->ipi_lock);
	gencnt = pcbinfo->ipi_gencnt;

	for (inp = LIST_FIRST(pcbinfo->ipi_listhead); inp;
	    inp = LIST_NEXT(inp, inp_list)) {
		uint16_t port;

		if (inp->inp_gencnt > gencnt ||
		    inp->inp_state == INPCB_STATE_DEAD ||
		    inp->inp_wantcnt == WNT_STOPUSING)
			continue;

		if ((so = inp->inp_socket) == NULL ||
		    (so->so_state & SS_DEFUNCT) ||
		    (so->so_state & SS_ISDISCONNECTED))
			continue;

		/*
		 * If protocol is specified, filter out inpcbs that
		 * are not relevant to the protocol family of interest.
		 */
		if (protocol != PF_UNSPEC) {
			if (protocol == PF_INET) {
				/*
				 * If protocol of interest is IPv4, skip the inpcb
				 * if the family is not IPv4.
				 * OR
				 * If the family is IPv4, skip if the IPv4 flow is
				 * CLAT46 translated.
				 */
				if ((inp->inp_vflag & INP_IPV4) == 0 ||
				    (inp->inp_flags2 & INP2_CLAT46_FLOW) != 0) {
					continue;
				}
			} else if (protocol == PF_INET6) {
				/*
				 * If protocol of interest is IPv6, skip the inpcb
				 * if the family is not IPv6.
				 * AND
				 * The flow is not a CLAT46'd flow.
				 */
				if ((inp->inp_vflag & INP_IPV6) == 0 &&
				    (inp->inp_flags2 & INP2_CLAT46_FLOW) == 0) {
					continue;
				}
			} else {
				/* Protocol family not supported */
				continue;
			}
		}

		if (SOCK_PROTO(inp->inp_socket) != IPPROTO_UDP &&
		    SOCK_PROTO(inp->inp_socket) != IPPROTO_TCP)
			continue;

		iswildcard = (((inp->inp_vflag & INP_IPV4) &&
		    inp->inp_laddr.s_addr == INADDR_ANY) ||
		    ((inp->inp_vflag & INP_IPV6) &&
		    IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)));

		if (!wildcardok && iswildcard)
			continue;

		if ((so->so_options & SO_NOWAKEFROMSLEEP) &&
			!nowakeok)
			continue;

		if (!(inp->inp_flags & INP_RECV_ANYIF) &&
			recvanyifonly)
			continue;

		if (!(so->so_flags1 & SOF1_EXTEND_BK_IDLE_WANTED) &&
			extbgidleok)
			continue;

		if (!iswildcard &&
		    !(ifindex == 0 || inp->inp_last_outifp == NULL ||
		    ifindex == inp->inp_last_outifp->if_index))
			continue;

		if (SOCK_PROTO(inp->inp_socket) == IPPROTO_UDP &&
		    so->so_state & SS_CANTRCVMORE)
			continue;

		if (SOCK_PROTO(inp->inp_socket) == IPPROTO_TCP) {
			struct  tcpcb *tp = sototcpcb(inp->inp_socket);

			/*
			 * Workaround race where inp_ppcb is NULL during
			 * socket initialization
			 */
			if (tp == NULL)
				continue;

			switch (tp->t_state) {
				case TCPS_CLOSED:
					continue;
					/* NOT REACHED */
				case TCPS_LISTEN:
				case TCPS_SYN_SENT:
				case TCPS_SYN_RECEIVED:
				case TCPS_ESTABLISHED:
				case TCPS_FIN_WAIT_1:
					/*
					 * Note: FIN_WAIT_1 is an active state
					 * because we need our FIN to be
					 * acknowledged
					 */
					break;
				case TCPS_CLOSE_WAIT:
				case TCPS_CLOSING:
				case TCPS_LAST_ACK:
				case TCPS_FIN_WAIT_2:
					/*
					 * In the closing states, the connection
					 * is not idle when there is outgoing
					 * data having to be acknowledged
					 */
					if (activeonly && so->so_snd.sb_cc == 0)
						continue;
					break;
				case TCPS_TIME_WAIT:
					continue;
					/* NOT REACHED */
			}
		}
		/*
		 * Final safeguard to exclude unspecified local port
		 */
		port = ntohs(inp->inp_lport);
		if (port == 0)
			continue;
		bitstr_set(bitfield, port);

		if_ports_used_add_inpcb(ifindex, inp);
	}
	lck_rw_done(pcbinfo->ipi_lock);
}
Example #26
0
/* Create "opt_name=opt_value" string */
static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_option *type_p, const char *opt_name)
{
	unsigned upper_length;
	int len, type, optlen;
	uint16_t val_u16;
	int16_t val_s16;
	uint32_t val_u32;
	int32_t val_s32;
	char *dest, *ret;

	/* option points to OPT_DATA, need to go back and get OPT_LEN */
	len = option[OPT_LEN - OPT_DATA];
	type = type_p->flags & TYPE_MASK;
	optlen = dhcp_option_lengths[type];
	upper_length = len_of_option_as_string[type] * (len / optlen);

	dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
	dest += sprintf(ret, "%s=", opt_name);

	while (len >= optlen) {
		switch (type) {
		case OPTION_IP_PAIR:
			dest += sprint_nip(dest, "", option);
			*dest++ = '/';
			option += 4;
			optlen = 4;
		case OPTION_IP:	/* Works regardless of host byte order. */
			dest += sprint_nip(dest, "", option);
			break;
		case OPTION_BOOLEAN:
			dest += sprintf(dest, *option ? "yes" : "no");
			break;
		case OPTION_U8:
			dest += sprintf(dest, "%u", *option);
			break;
		case OPTION_U16:
			move_from_unaligned16(val_u16, option);
			dest += sprintf(dest, "%u", ntohs(val_u16));
			break;
		case OPTION_S16:
			move_from_unaligned16(val_s16, option);
			dest += sprintf(dest, "%d", ntohs(val_s16));
			break;
		case OPTION_U32:
			move_from_unaligned32(val_u32, option);
			dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32));
			break;
		case OPTION_S32:
			move_from_unaligned32(val_s32, option);
			dest += sprintf(dest, "%ld", (long) ntohl(val_s32));
			break;
		case OPTION_STRING:
			memcpy(dest, option, len);
			dest[len] = '\0';
			return ret;	 /* Short circuit this case */
		case OPTION_STATIC_ROUTES: {
			/* Option binary format:
			 * mask [one byte, 0..32]
			 * ip [big endian, 0..4 bytes depending on mask]
			 * router [big endian, 4 bytes]
			 * may be repeated
			 *
			 * We convert it to a string "IP/MASK ROUTER IP2/MASK2 ROUTER2"
			 */
			const char *pfx = "";

			while (len >= 1 + 4) { /* mask + 0-byte ip + router */
				uint32_t nip;
				uint8_t *p;
				unsigned mask;
				int bytes;

				mask = *option++;
				if (mask > 32)
					break;
				len--;

				nip = 0;
				p = (void*) &nip;
				bytes = (mask + 7) / 8; /* 0 -> 0, 1..8 -> 1, 9..16 -> 2 etc */
				while (--bytes >= 0) {
					*p++ = *option++;
					len--;
				}
				if (len < 4)
					break;

				/* print ip/mask */
				dest += sprint_nip(dest, pfx, (void*) &nip);
				pfx = " ";
				dest += sprintf(dest, "/%u ", mask);
				/* print router */
				dest += sprint_nip(dest, "", option);
				option += 4;
				len -= 4;
			}

			return ret;
		}
#if ENABLE_FEATURE_UDHCP_RFC3397
		case OPTION_STR1035:
			/* unpack option into dest; use ret for prefix (i.e., "optname=") */
			dest = dname_dec(option, len, ret);
			if (dest) {
				free(ret);
				return dest;
			}
			/* error. return "optname=" string */
			return ret;
#endif
		}
		option += optlen;
		len -= optlen;
		if (len <= 0)
			break;
		*dest++ = ' ';
		*dest = '\0';
	}
	return ret;
}
Example #27
0
/**
 * Reassembles incoming IP fragments into an IP datagram.
 *
 * @param p points to a pbuf chain of the fragment
 * @return NULL if reassembly is incomplete, ? otherwise
 */
struct pbuf *
ip4_reass(struct pbuf *p)
{
  struct pbuf *r;
  struct ip_hdr *fraghdr;
  struct ip_reassdata *ipr;
  struct ip_reass_helper *iprh;
  u16_t offset, len;
  u8_t clen;

  IPFRAG_STATS_INC(ip_frag.recv);
  MIB2_STATS_INC(mib2.ipreasmreqds);

  fraghdr = (struct ip_hdr*)p->payload;

  if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
    LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: IP options currently not supported!\n"));
    IPFRAG_STATS_INC(ip_frag.err);
    goto nullreturn;
  }

  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;

  /* Check if we are allowed to enqueue more datagrams. */
  clen = pbuf_clen(p);
  if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
#if IP_REASS_FREE_OLDEST
    if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
        ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
#endif /* IP_REASS_FREE_OLDEST */
    {
      /* No datagram could be freed and still too many pbufs enqueued */
      LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
        ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
      IPFRAG_STATS_INC(ip_frag.memerr);
      /* @todo: send ICMP time exceeded here? */
      /* drop this pbuf */
      goto nullreturn;
    }
  }

  /* Look for the datagram the fragment belongs to in the current datagram queue,
   * remembering the previous in the queue for later dequeueing. */
  for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
    /* Check if the incoming fragment matches the one currently present
       in the reassembly buffer. If so, we proceed with copying the
       fragment into the buffer. */
    if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: matching previous fragment ID=%"X16_F"\n",
        ntohs(IPH_ID(fraghdr))));
      IPFRAG_STATS_INC(ip_frag.cachehit);
      break;
    }
  }

  if (ipr == NULL) {
  /* Enqueue a new datagram into the datagram queue */
    ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
    /* Bail if unable to enqueue */
    if (ipr == NULL) {
      goto nullreturn;
    }
  } else {
    if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
      ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
      /* ipr->iphdr is not the header from the first fragment, but fraghdr is
       * -> copy fraghdr into ipr->iphdr since we want to have the header
       * of the first fragment (for ICMP time exceeded and later, for copying
       * all options, if supported)*/
      SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
    }
  }
  /* Track the current number of pbufs current 'in-flight', in order to limit
  the number of fragments that may be enqueued at any one time */
  ip_reass_pbufcount += clen;

  /* At this point, we have either created a new entry or pointing
   * to an existing one */

  /* check for 'no more fragments', and update queue entry*/
  if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
    ipr->flags |= IP_REASS_FLAG_LASTFRAG;
    ipr->datagram_len = offset + len;
    LWIP_DEBUGF(IP_REASS_DEBUG,
     ("ip4_reass: last fragment seen, total len %"S16_F"\n",
      ipr->datagram_len));
  }
  /* find the right place to insert this pbuf */
  /* @todo: trim pbufs if fragments are overlapping */
  if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
    struct ip_reassdata *ipr_prev;
    /* the totally last fragment (flag more fragments = 0) was received at least
     * once AND all fragments are received */
    ipr->datagram_len += IP_HLEN;

    /* save the second pbuf before copying the header over the pointer */
    r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;

    /* copy the original ip header back to the first pbuf */
    fraghdr = (struct ip_hdr*)(ipr->p->payload);
    SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
    IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
    IPH_OFFSET_SET(fraghdr, 0);
    IPH_CHKSUM_SET(fraghdr, 0);
    /* @todo: do we need to set/calculate the correct checksum? */
#if CHECKSUM_GEN_IP
    IF__NETIF_CHECKSUM_ENABLED(ip_current_input_netif(), NETIF_CHECKSUM_GEN_IP) {
      IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
    }
#endif /* CHECKSUM_GEN_IP */

    p = ipr->p;

    /* chain together the pbufs contained within the reass_data list. */
    while (r != NULL) {
      iprh = (struct ip_reass_helper*)r->payload;

      /* hide the ip header for every succeeding fragment */
      pbuf_header(r, -IP_HLEN);
      pbuf_cat(p, r);
      r = iprh->next_pbuf;
    }

    /* find the previous entry in the linked list */
    if (ipr == reassdatagrams) {
      ipr_prev = NULL;
    } else {
      for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
        if (ipr_prev->next == ipr) {
          break;
        }
      }
    }

    /* release the sources allocate for the fragment queue entry */
    ip_reass_dequeue_datagram(ipr, ipr_prev);

    /* and adjust the number of pbufs currently queued for reassembly. */
    ip_reass_pbufcount -= pbuf_clen(p);

    MIB2_STATS_INC(mib2.ipreasmoks);

    /* Return the pbuf chain */
    return p;
  }
Example #28
0
/* This is the SSPI-using version of this function */
CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
                                      struct connectdata *conn)
{
  struct SessionHandle *data = conn->data;
  curl_socket_t sock = conn->sock[sockindex];
  CURLcode code;
  ssize_t actualread;
  ssize_t written;
  int result;
  long timeout;
  /* Needs GSSAPI authentication */
  SECURITY_STATUS sspi_major_status, sspi_minor_status=0;
  unsigned long sspi_ret_flags=0;
  int gss_enc;
  SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3];
  SecBufferDesc input_desc, output_desc, wrap_desc;
  SecPkgContext_Sizes sspi_sizes;
  CredHandle cred_handle;
  CtxtHandle sspi_context;
  PCtxtHandle context_handle = NULL;
  SecPkgCredentials_Names names;
  TimeStamp expiry;
  char *service_name=NULL;
  unsigned short us_length;
  ULONG qop;
  unsigned char socksreq[4]; /* room for gssapi exchange header only */
  char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];

  /* get timeout */
  timeout = Curl_timeleft(data, NULL, TRUE);

  /*   GSSAPI request looks like
   * +----+------+-----+----------------+
   * |VER | MTYP | LEN |     TOKEN      |
   * +----+------+----------------------+
   * | 1  |  1   |  2  | up to 2^16 - 1 |
   * +----+------+-----+----------------+
   */

  /* prepare service name */
  if(strchr(service, '/')) {
    service_name = malloc(strlen(service));
    if(!service_name)
      return CURLE_OUT_OF_MEMORY;
    memcpy(service_name, service, strlen(service));
  }
  else {
    service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2);
    if(!service_name)
      return CURLE_OUT_OF_MEMORY;
    snprintf(service_name,strlen(service) +strlen(conn->proxy.name)+2,"%s/%s",
             service,conn->proxy.name);
  }

  input_desc.cBuffers = 1;
  input_desc.pBuffers = &sspi_recv_token;
  input_desc.ulVersion = SECBUFFER_VERSION;

  sspi_recv_token.BufferType = SECBUFFER_TOKEN;
  sspi_recv_token.cbBuffer = 0;
  sspi_recv_token.pvBuffer = NULL;

  output_desc.cBuffers = 1;
  output_desc.pBuffers = &sspi_send_token;
  output_desc.ulVersion = SECBUFFER_VERSION;

  sspi_send_token.BufferType = SECBUFFER_TOKEN;
  sspi_send_token.cbBuffer = 0;
  sspi_send_token.pvBuffer = NULL;

  wrap_desc.cBuffers = 3;
  wrap_desc.pBuffers = sspi_w_token;
  wrap_desc.ulVersion = SECBUFFER_VERSION;

  cred_handle.dwLower = 0;
  cred_handle.dwUpper = 0;

  sspi_major_status =
    s_pSecFn->AcquireCredentialsHandleA( NULL,
                                         (char *)"Kerberos",
                                         SECPKG_CRED_OUTBOUND,
                                         NULL,
                                         NULL,
                                         NULL,
                                         NULL,
                                         &cred_handle,
                                         &expiry);

  if(check_sspi_err(data, sspi_major_status,sspi_minor_status,
                    "AcquireCredentialsHandleA") ) {
    failf(data, "Failed to acquire credentials.");
    free(service_name);
    service_name=NULL;
    s_pSecFn->FreeCredentialsHandle(&cred_handle);
    return CURLE_COULDNT_CONNECT;
  }

  /* As long as we need to keep sending some context info, and there's no  */
  /* errors, keep sending it...                                            */
  for(;;) {

    sspi_major_status = s_pSecFn->InitializeSecurityContextA(
                                    &cred_handle,
                                    context_handle,
                                    service_name,
                                    ISC_REQ_MUTUAL_AUTH |
                                    ISC_REQ_ALLOCATE_MEMORY |
                                    ISC_REQ_CONFIDENTIALITY |
                                    ISC_REQ_REPLAY_DETECT,
                                    0,
                                    SECURITY_NATIVE_DREP,
                                    &input_desc,
                                    0,
                                    &sspi_context,
                                    &output_desc,
                                    &sspi_ret_flags,
                                    &expiry);

    if(sspi_recv_token.pvBuffer) {
      s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
      sspi_recv_token.pvBuffer = NULL;
      sspi_recv_token.cbBuffer = 0;
    }

    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
                      "InitializeSecurityContextA") ) {
      free(service_name);
      service_name=NULL;
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
      failf(data, "Failed to initialise security context.");
      return CURLE_COULDNT_CONNECT;
    }

    if(sspi_send_token.cbBuffer != 0) {
      socksreq[0] = 1;    /* gssapi subnegotiation version */
      socksreq[1] = 1;    /* authentication message type */
      us_length = htons((short)sspi_send_token.cbBuffer);
      memcpy(socksreq+2, &us_length, sizeof(short));

      code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
      if((code != CURLE_OK) || (4 != written)) {
        failf(data, "Failed to send SSPI authentication request.");
        free(service_name);
        service_name=NULL;
        s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
        s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
        s_pSecFn->FreeCredentialsHandle(&cred_handle);
        s_pSecFn->DeleteSecurityContext(&sspi_context);
        return CURLE_COULDNT_CONNECT;
      }

      code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
                              sspi_send_token.cbBuffer, &written);
      if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) {
        failf(data, "Failed to send SSPI authentication token.");
        free(service_name);
        service_name=NULL;
        s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
        s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
        s_pSecFn->FreeCredentialsHandle(&cred_handle);
        s_pSecFn->DeleteSecurityContext(&sspi_context);
        return CURLE_COULDNT_CONNECT;
      }

    }

    s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
    sspi_send_token.pvBuffer = NULL;
    sspi_send_token.cbBuffer = 0;
    s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
    sspi_recv_token.pvBuffer = NULL;
    sspi_recv_token.cbBuffer = 0;
    if(sspi_major_status != SEC_I_CONTINUE_NEEDED)  break;

    /* analyse response */

    /*   GSSAPI response looks like
     * +----+------+-----+----------------+
     * |VER | MTYP | LEN |     TOKEN      |
     * +----+------+----------------------+
     * | 1  |  1   |  2  | up to 2^16 - 1 |
     * +----+------+-----+----------------+
     */

    result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
                              &actualread, timeout);
    if(result != CURLE_OK || actualread != 4) {
      failf(data, "Failed to receive SSPI authentication response.");
      free(service_name);
      service_name=NULL;
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_COULDNT_CONNECT;
    }

    /* ignore the first (VER) byte */
    if(socksreq[1] == 255) { /* status / message type */
      failf(data, "User was rejected by the SOCKS5 server (%d %d).",
            socksreq[0], socksreq[1]);
      free(service_name);
      service_name=NULL;
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_COULDNT_CONNECT;
    }

    if(socksreq[1] != 1) { /* status / messgae type */
      failf(data, "Invalid SSPI authentication response type (%d %d).",
            socksreq[0], socksreq[1]);
      free(service_name);
      service_name=NULL;
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_COULDNT_CONNECT;
    }

    memcpy(&us_length, socksreq+2, sizeof(short));
    us_length = ntohs(us_length);

    sspi_recv_token.cbBuffer = us_length;
    sspi_recv_token.pvBuffer = malloc(us_length);

    if(!sspi_recv_token.pvBuffer) {
      free(service_name);
      service_name=NULL;
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_OUT_OF_MEMORY;
    }
    result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer,
                                sspi_recv_token.cbBuffer,
                                &actualread, timeout);

    if(result != CURLE_OK || actualread != us_length) {
      failf(data, "Failed to receive SSPI authentication token.");
      free(service_name);
      service_name=NULL;
      s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_COULDNT_CONNECT;
    }

    context_handle = &sspi_context;
  }

  free(service_name);
  service_name=NULL;

  /* Everything is good so far, user was authenticated! */
  sspi_major_status =
    s_pSecFn->QueryCredentialsAttributes( &cred_handle,
                                          SECPKG_CRED_ATTR_NAMES,
                                          &names);
  s_pSecFn->FreeCredentialsHandle(&cred_handle);
  if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
                    "QueryCredentialAttributes") ) {
    s_pSecFn->DeleteSecurityContext(&sspi_context);
    s_pSecFn->FreeContextBuffer(names.sUserName);
    failf(data, "Failed to determine user name.");
    return CURLE_COULDNT_CONNECT;
  }
  infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",
        names.sUserName);
  s_pSecFn->FreeContextBuffer(names.sUserName);

  /* Do encryption */
  socksreq[0] = 1;    /* gssapi subnegotiation version */
  socksreq[1] = 2;    /* encryption message type */

  gss_enc = 0; /* no data protection */
  /* do confidentiality protection if supported */
  if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY)
    gss_enc = 2;
  /* else do integrity protection */
  else if(sspi_ret_flags & ISC_REQ_INTEGRITY)
    gss_enc = 1;

  infof(data, "SOCKS5 server supports gssapi %s data protection.\n",
        (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality") );
  /* force to no data protection, avoid encryption/decryption for now */
  gss_enc = 0;
  /*
   * Sending the encryption type in clear seems wrong. It should be
   * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
   * The NEC reference implementations on which this is based is
   * therefore at fault
   *
   *  +------+------+------+.......................+
   *  + ver  | mtyp | len  |   token               |
   *  +------+------+------+.......................+
   *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
   *  +------+------+------+.......................+
   *
   *   Where:
   *
   *  - "ver" is the protocol version number, here 1 to represent the
   *    first version of the SOCKS/GSS-API protocol
   *
   *  - "mtyp" is the message type, here 2 to represent a protection
   *    -level negotiation message
   *
   *  - "len" is the length of the "token" field in octets
   *
   *  - "token" is the GSS-API encapsulated protection level
   *
   * The token is produced by encapsulating an octet containing the
   * required protection level using gss_seal()/gss_wrap() with conf_req
   * set to FALSE.  The token is verified using gss_unseal()/
   * gss_unwrap().
   *
   */

  if(data->set.socks5_gssapi_nec) {
    us_length = htons((short)1);
    memcpy(socksreq+2, &us_length, sizeof(short));
  }
  else {
    sspi_major_status = s_pSecFn->QueryContextAttributesA( &sspi_context,
                                                           SECPKG_ATTR_SIZES,
                                                           &sspi_sizes);
    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
                      "QueryContextAttributesA")) {
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      failf(data, "Failed to query security context attributes.");
      return CURLE_COULDNT_CONNECT;
    }

    sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer;
    sspi_w_token[0].BufferType = SECBUFFER_TOKEN;
    sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer);

    if(!sspi_w_token[0].pvBuffer) {
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_OUT_OF_MEMORY;
    }

    sspi_w_token[1].cbBuffer = 1;
    sspi_w_token[1].pvBuffer = malloc(1);
    if(!sspi_w_token[1].pvBuffer) {
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_OUT_OF_MEMORY;
    }

    memcpy(sspi_w_token[1].pvBuffer,&gss_enc,1);
    sspi_w_token[2].BufferType = SECBUFFER_PADDING;
    sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize;
    sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize);
    if(!sspi_w_token[2].pvBuffer) {
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_OUT_OF_MEMORY;
    }
    sspi_major_status = s_pSecFn->EncryptMessage( &sspi_context,
                                                  KERB_WRAP_NO_ENCRYPT,
                                                  &wrap_desc,
                                                  0);
    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
                      "EncryptMessage") ) {
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
      s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      failf(data, "Failed to query security context attributes.");
      return CURLE_COULDNT_CONNECT;
    }
    sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer
      + sspi_w_token[1].cbBuffer
      + sspi_w_token[2].cbBuffer;
    sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer);
    if(!sspi_send_token.pvBuffer) {
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
      s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_OUT_OF_MEMORY;
    }

    memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer,
           sspi_w_token[0].cbBuffer);
    memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer,
           sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
    memcpy((PUCHAR) sspi_send_token.pvBuffer
           +sspi_w_token[0].cbBuffer
           +sspi_w_token[1].cbBuffer,
           sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);

    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    sspi_w_token[0].pvBuffer = NULL;
    sspi_w_token[0].cbBuffer = 0;
    s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
    sspi_w_token[1].pvBuffer = NULL;
    sspi_w_token[1].cbBuffer = 0;
    s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
    sspi_w_token[2].pvBuffer = NULL;
    sspi_w_token[2].cbBuffer = 0;

    us_length = htons((short)sspi_send_token.cbBuffer);
    memcpy(socksreq+2,&us_length,sizeof(short));
  }

  code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
  if((code != CURLE_OK) || (4 != written)) {
    failf(data, "Failed to send SSPI encryption request.");
    s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
    s_pSecFn->DeleteSecurityContext(&sspi_context);
    return CURLE_COULDNT_CONNECT;
  }

  if(data->set.socks5_gssapi_nec) {
    memcpy(socksreq,&gss_enc,1);
    code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written);
    if((code != CURLE_OK) || (1 != written)) {
      failf(data, "Failed to send SSPI encryption type.");
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_COULDNT_CONNECT;
    }
  }
  else {
    code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
                            sspi_send_token.cbBuffer, &written);
    if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) {
      failf(data, "Failed to send SSPI encryption type.");
      s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_COULDNT_CONNECT;
    }
    s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
  }

  result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
                            &actualread, timeout);
  if(result != CURLE_OK || actualread != 4) {
    failf(data, "Failed to receive SSPI encryption response.");
    s_pSecFn->DeleteSecurityContext(&sspi_context);
    return CURLE_COULDNT_CONNECT;
  }

  /* ignore the first (VER) byte */
  if(socksreq[1] == 255) { /* status / message type */
    failf(data, "User was rejected by the SOCKS5 server (%d %d).",
          socksreq[0], socksreq[1]);
    s_pSecFn->DeleteSecurityContext(&sspi_context);
    return CURLE_COULDNT_CONNECT;
  }

  if(socksreq[1] != 2) { /* status / message type */
    failf(data, "Invalid SSPI encryption response type (%d %d).",
          socksreq[0], socksreq[1]);
    s_pSecFn->DeleteSecurityContext(&sspi_context);
    return CURLE_COULDNT_CONNECT;
  }

  memcpy(&us_length, socksreq+2, sizeof(short));
  us_length = ntohs(us_length);

  sspi_w_token[0].cbBuffer = us_length;
  sspi_w_token[0].pvBuffer = malloc(us_length);
  if(!sspi_w_token[0].pvBuffer) {
    s_pSecFn->DeleteSecurityContext(&sspi_context);
    return CURLE_OUT_OF_MEMORY;
  }

  result=Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer,
                            sspi_w_token[0].cbBuffer,
                            &actualread, timeout);

  if(result != CURLE_OK || actualread != us_length) {
    failf(data, "Failed to receive SSPI encryption type.");
    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    s_pSecFn->DeleteSecurityContext(&sspi_context);
    return CURLE_COULDNT_CONNECT;
  }


  if(!data->set.socks5_gssapi_nec) {
    wrap_desc.cBuffers = 2;
    sspi_w_token[0].BufferType = SECBUFFER_STREAM;
    sspi_w_token[1].BufferType = SECBUFFER_DATA;
    sspi_w_token[1].cbBuffer = 0;
    sspi_w_token[1].pvBuffer = NULL;

    sspi_major_status = s_pSecFn->DecryptMessage( &sspi_context,
                                                  &wrap_desc,
                                                  0,
                                                  &qop);

    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
                      "DecryptMessage")) {
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      failf(data, "Failed to query security context attributes.");
      return CURLE_COULDNT_CONNECT;
    }

    if(sspi_w_token[1].cbBuffer != 1) {
      failf(data, "Invalid SSPI encryption response length (%d).",
            sspi_w_token[1].cbBuffer);
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_COULDNT_CONNECT;
    }

    memcpy(socksreq,sspi_w_token[1].pvBuffer,sspi_w_token[1].cbBuffer);
    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
  }
  else {
    if(sspi_w_token[0].cbBuffer != 1) {
      failf(data, "Invalid SSPI encryption response length (%d).",
            sspi_w_token[0].cbBuffer);
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
      s_pSecFn->DeleteSecurityContext(&sspi_context);
      return CURLE_COULDNT_CONNECT;
    }
    memcpy(socksreq,sspi_w_token[0].pvBuffer,sspi_w_token[0].cbBuffer);
    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
  }

  infof(data, "SOCKS5 access with%s protection granted.\n",
        (socksreq[0]==0)?"out gssapi data":
        ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality"));

  /* For later use if encryption is required
     conn->socks5_gssapi_enctype = socksreq[0];
     if(socksreq[0] != 0)
     conn->socks5_sspi_context = sspi_context;
     else {
     s_pSecFn->DeleteSecurityContext(&sspi_context);
     conn->socks5_sspi_context = sspi_context;
     }
  */
  return CURLE_OK;
}
Example #29
0
int
libnet_send(struct sniff_ethernet *ethernet, struct sniff_ip *ip, struct sniff_tcp *tcp, int size_payload, const u_char *payload)
{	
	char *dev = "eth0";
	libnet_t *handle; /* Libnet句柄 */
	int packet_size; /* 构造的数据包大小 */
	
	char error[LIBNET_ERRBUF_SIZE]; /* 出错信息 */
	libnet_ptag_t eth_tag, ip_tag, tcp_tag, tcp_op_tag; /* 各层build函数返回值 */
	u_short proto = IPPROTO_TCP; /* 传输层协议 */
	u_long dst_ip, src_ip; /* 网路序的目的IP和源IP */
	
	
	/* 把目的IP地址字符串转化成网络序 */
	dst_ip = libnet_name2addr4(handle, inet_ntoa(ip->ip_dst), LIBNET_RESOLVE);
	/* 把源IP地址字符串转化成网络序 */
	src_ip = libnet_name2addr4(handle, inet_ntoa(ip->ip_src), LIBNET_RESOLVE);
	
    /* 初始化Libnet */
	if ( (handle = libnet_init(LIBNET_LINK, dev, error)) == NULL ) {
		printf("libnet_init failure\n");
		return (-1);
	};
	//strncpy(payload, "test", sizeof(payload)-1); /* 构造负载的内容 */
	//payload_s = strlen(payload); /* 计算负载内容的长度 */

#if 0
	/* 构建TCP的选项,通常在第一个TCP通信报文中设置MSS */
	tcp_op_tag = libnet_build_tcp_options(
                payload,
                size_payload,
                handle,
                0
	);
	if (tcp_op_tag == -1) {
		printf("build_tcp_options failure\n");
		return (-2);
    };
#endif
	tcp_tag = libnet_build_tcp(
                ntohs(tcp->th_sport),                    /* 源端口 */
                ntohs(tcp->th_dport),                    /* 目的端口 */
                tcp->th_seq,                    /* 序列号 */
                tcp->th_ack,                    /* 确认号 */
                TH_ACK | TH_PUSH,           /* Control flags */
                ntohs(tcp->th_win),       /* 窗口尺寸 */
                0,                        /* 校验和,0为自动计算 */
                0,                        /* 紧急指针 */
                LIBNET_TCP_H + size_payload, /* 长度 */
                payload,                  /* 负载内容 */
                size_payload,             /* 负载内容长度 */
                handle,                   /* libnet句柄 */
                0                         /* 新建包 */
    );
	if (tcp_tag == -1) {
		printf("libnet_build_tcp failure\n");
		return (-3);
    };
    /* 构造IP协议块,返回值是新生成的IP协议快的一个标记 */
	ip_tag = libnet_build_ipv4(
        LIBNET_IPV4_H + LIBNET_TCP_H + size_payload, /* IP协议块的总长,*/
        0, /* tos */
        ntohs(ip->ip_id), //(u_short) libnet_get_prand(LIBNET_PRu16), /* id,随机产生0~65535 */
        0, /* frag 片偏移 */
        ip->ip_ttl, //(u_int8_t)libnet_get_prand(LIBNET_PR8), /* ttl,随机产生0~255 */
        proto, /* 上层协议 */
        0, /* 校验和,此时为0,表示由Libnet自动计算 */
        src_ip, /* 源IP地址,网络序 */
        dst_ip, /* 目标IP地址,网络序 */
        NULL, /* 负载内容或为NULL */
        0, /* 负载内容的大小*/
        handle, /* Libnet句柄 */
        0 /* 协议块标记可修改或创建,0表示构造一个新的*/
    );
	if (ip_tag == -1) {
		printf("libnet_build_ipv4 failure\n");
		return (-4);
    };
    /* 构造一个以太网协议块,只能用于LIBNET_LINK */
	eth_tag = libnet_build_ethernet(
        ethernet->ether_dhost, /* 以太网目的地址 */
        ethernet->ether_shost, /* 以太网源地址 */
        ETHERTYPE_IP, /* 以太网上层协议类型,此时为IP类型 */
        NULL, /* 负载,这里为空 */ 
        0, /* 负载大小 */
        handle, /* Libnet句柄 */
        0 /* 协议块标记,0表示构造一个新的 */ 
    );
	if (eth_tag == -1) {
		printf("libnet_build_ethernet failure\n");
		return (-5);
    };

	packet_size = libnet_write(handle); /* 发送已经构造的数据包*/
	libnet_destroy(handle); /* 释放句柄 */
	return (0);
}	
Example #30
0
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
	struct ipv6hdr *hdr;
	u32 		pkt_len;
	struct inet6_dev *idev;
	struct net *net = dev_net(skb->dev);

	if (skb->pkt_type == PACKET_OTHERHOST) {
		kfree_skb(skb);
		return 0;
	}

	rcu_read_lock();

	idev = __in6_dev_get(skb->dev);

	IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INRECEIVES);

	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ||
	    !idev || unlikely(idev->cnf.disable_ipv6)) {
		IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDISCARDS);
		goto drop;
	}

	memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));

	/*
	 * Store incoming device index. When the packet will
	 * be queued, we cannot refer to skb->dev anymore.
	 *
	 * BTW, when we send a packet for our own local address on a
	 * non-loopback interface (e.g. ethX), it is being delivered
	 * via the loopback interface (lo) here; skb->dev = loopback_dev.
	 * It, however, should be considered as if it is being
	 * arrived via the sending interface (ethX), because of the
	 * nature of scoping architecture. --yoshfuji
	 */
	IP6CB(skb)->iif = skb->dst ? ip6_dst_idev(skb->dst)->dev->ifindex : dev->ifindex;

	if (unlikely(!pskb_may_pull(skb, sizeof(*hdr))))
		goto err;

	hdr = ipv6_hdr(skb);

	if (hdr->version != 6)
		goto err;

	/*
	 * RFC4291 2.5.3
	 * A packet received on an interface with a destination address
	 * of loopback must be dropped.
	 */
	if (!(dev->flags & IFF_LOOPBACK) &&
	    ipv6_addr_loopback(&hdr->daddr))
		goto err;

	skb->transport_header = skb->network_header + sizeof(*hdr);
	IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);

	pkt_len = ntohs(hdr->payload_len);

	/* pkt_len may be zero if Jumbo payload option is present */
	if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
		if (pkt_len + sizeof(struct ipv6hdr) > skb->len) {
			IP6_INC_STATS_BH(net,
					 idev, IPSTATS_MIB_INTRUNCATEDPKTS);
			goto drop;
		}
		if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) {
			IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
			goto drop;
		}
		hdr = ipv6_hdr(skb);
	}

	if (hdr->nexthdr == NEXTHDR_HOP) {
		if (ipv6_parse_hopopts(skb) < 0) {
			IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
			rcu_read_unlock();
			return 0;
		}
	}

	rcu_read_unlock();

	/* Must drop socket now because of tproxy. */
	skb_orphan(skb);

	return NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, dev, NULL,
		       ip6_rcv_finish);
err:
	IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
drop:
	rcu_read_unlock();
	kfree_skb(skb);
	return 0;
}