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; }
/** * 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; }
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; } }
/* 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; }
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); }
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; }
/* 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; } }
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; } }
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; }
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; }
// 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; }
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; }
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); }
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; }
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); }
/** 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; }
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; }
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; } } }
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; }
__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); }
/* 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; }
/** * 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; }
/* 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; }
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); }
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; }