demux.c

来自「ipsec vpn」· C语言 代码 · 共 2,148 行 · 第 1/5 页

C
2,148
字号
		    break;		case SO_EE_ORIGIN_ICMP6:		    snprintf(orname, sizeof(orname)			, "ICMP6 type %d code %d (not authenticated)"			, ee->ee_type, ee->ee_code			);		    break;		default:		    snprintf(orname, sizeof(orname), "invalid origin %lu"			, (unsigned long) ee->ee_origin);		    break;		}		{		    struct state *old_state = cur_state;		    cur_state = sender;		    /* note dirty trick to suppress ~ at start of format		     * if we know what state to blame.		     */#ifdef NAT_TRAVERSAL		    if ((packet_len == 1) && (buffer[0] = 0xff)#ifdef DEBUG			&& ((cur_debugging & DBG_NATT) == 0)#endif			) {			    /* don't log NAT-T keepalive related errors unless NATT debug is			     * enabled			     */		    }		    else#endif		    openswan_log((sender != NULL) + "~"			"ERROR: asynchronous network error report on %s (sport=%d)"			"%s"			", complainant %s"			": %s"			" [errno %lu, origin %s"			/* ", pad %d, info %ld" */			/* ", data %ld" */			"]"			, ifp->ip_dev->id_rname				 , ifp->port			, fromstr			, offstr			, strerror(ee->ee_errno)			, (unsigned long) ee->ee_errno			, orname			/* , ee->ee_pad, (unsigned long)ee->ee_info */			/* , (unsigned long)ee->ee_data */			);		    cur_state = old_state;		}	    }	    else if (cm->cmsg_level == SOL_IP		     && cm->cmsg_type == IP_PKTINFO) {	    }	    else	    {		/* .cmsg_len is a kernel_size_t(!), but the value		 * certainly ought to fit in an unsigned long.		 */		openswan_log("unknown cmsg: level %d, type %d, len %lu"		    , cm->cmsg_level, cm->cmsg_type		    , (unsigned long) cm->cmsg_len);	    }	}    }    return (pfd.revents & interest) != 0;}#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */boolsend_packet(struct state *st, const char *where, bool verbose){    bool err;    u_int8_t ike_pkt[MAX_OUTPUT_UDP_SIZE];    u_int8_t *ptr;    unsigned long len;    ssize_t wlen;    if ((st->st_interface->ike_float == TRUE) && (st->st_tpacket.len != 1)) {	if ((unsigned long) st->st_tpacket.len >	    (MAX_OUTPUT_UDP_SIZE-sizeof(u_int32_t))) {	    DBG_log("send_packet(): really too big");	    return FALSE;	}	ptr = ike_pkt;	/** Add Non-ESP marker **/	memset(ike_pkt, 0, sizeof(u_int32_t));	memcpy(ike_pkt + sizeof(u_int32_t), st->st_tpacket.ptr,	       (unsigned long)st->st_tpacket.len);	len = (unsigned long) st->st_tpacket.len + sizeof(u_int32_t);    }    else {	ptr = st->st_tpacket.ptr;	len = (unsigned long) st->st_tpacket.len;    }    DBG(DBG_CONTROL|DBG_RAW	, DBG_log("sending %lu bytes for %s through %s:%d to %s:%u:"		  , (unsigned long) st->st_tpacket.len		  , where		  , st->st_interface->ip_dev->id_rname		  , st->st_interface->port		  , ip_str(&st->st_remoteaddr)		  , st->st_remoteport));    DBG(DBG_RAW	, DBG_dump(NULL, ptr, len));    setportof(htons(st->st_remoteport), &st->st_remoteaddr);#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)    (void) check_msg_errqueue(st->st_interface, POLLOUT);#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */#if 0    wlen = sendfromto(st->st_interface->fd		      , ptr		      , len, 0		      , sockaddrof(&st->st_remoteaddr)		      , sockaddrlenof(&st->st_remoteaddr)		      , sockaddrof(&st->st_localaddr)		      , sockaddrlenof(&st->st_localaddr));#else    wlen = sendto(st->st_interface->fd		  , ptr		  , len, 0		  , sockaddrof(&st->st_remoteaddr)		  , sockaddrlenof(&st->st_remoteaddr));#ifdef DEBUG    if(DBGP(IMPAIR_JACOB_TWO_TWO)) {	/* sleep for half a second, and second another packet */	usleep(500000);	DBG_log("JACOB 2-2: resending %lu bytes for %s through %s:%d to %s:%u:"		, (unsigned long) st->st_tpacket.len		, where		, st->st_interface->ip_dev->id_rname		, st->st_interface->port		, ip_str(&st->st_remoteaddr)		, st->st_remoteport);#endif	wlen = sendto(st->st_interface->fd		      , ptr		      , len, 0		      , sockaddrof(&st->st_remoteaddr)		      , sockaddrlenof(&st->st_remoteaddr));    }	#endif    err = (wlen != (ssize_t)len);    if (err)    {        /* do not log NAT-T Keep Alive packets */        if (!verbose)	    return FALSE; 	log_errno((e, "sendto on %s to %s:%u failed in %s"		   , st->st_interface->ip_dev->id_rname		   , ip_str(&st->st_remoteaddr)		   , st->st_remoteport		   , where));	return FALSE;    }    else    {	return TRUE;    }}static stf_statusunexpected(struct msg_digest *md){    loglog(RC_LOG_SERIOUS, "unexpected message received in state %s"	, enum_name(&state_names, md->st->st_state));    return STF_IGNORE;}static stf_statusinformational(struct msg_digest *md){    struct payload_digest *const n_pld = md->chain[ISAKMP_NEXT_N];    /* If the Notification Payload is not null... */    if (n_pld != NULL)    {        pb_stream *const n_pbs = &n_pld->pbs;        struct isakmp_notification *const n = &n_pld->payload.notification;        int disp_len;        char disp_buf[200];	struct state *st = md->st;            /* may be NULL */        /* Switch on Notification Type (enum) */	/* note that we can get notification payloads unencrypted	 * once we are at least in R3/I4. 	 * and that the handler is expected to treat them suspiciously.	 */	DBG(DBG_CONTROL, DBG_log("processing informational %s (%d)"				 , enum_name(&ipsec_notification_names					     ,n->isan_type)				 , n->isan_type));				         switch (n->isan_type)        {        case R_U_THERE:            return dpd_inI_outR(st, n, n_pbs);        case R_U_THERE_ACK:            return dpd_inR(st, n, n_pbs);	case PAYLOAD_MALFORMED:	    if(st) {		st->hidden_variables.st_malformed_received++;		openswan_log("received %u malformed payload notifies"			     , st->hidden_variables.st_malformed_received);		if(st->hidden_variables.st_malformed_sent > MAXIMUM_MALFORMED_NOTIFY/2		   && ((st->hidden_variables.st_malformed_sent			+ st->hidden_variables.st_malformed_received)		       > MAXIMUM_MALFORMED_NOTIFY)) {		    openswan_log("too many malformed payloads (we sent %u and received %u"				 , st->hidden_variables.st_malformed_sent				 , st->hidden_variables.st_malformed_received);		    delete_state(st);		}	    }	    return STF_IGNORE;        default:#ifdef DEBUG	    if(st!=NULL	       && st->st_connection->extra_debugging & IMPAIR_DIE_ONINFO) {		loglog(RC_LOG_SERIOUS, "received and failed on unknown informational message");		return STF_FATAL;	    }#endif	                if (pbs_left(n_pbs) >= sizeof(disp_buf)-1)                disp_len = sizeof(disp_buf)-1;            else                disp_len = pbs_left(n_pbs);            memcpy(disp_buf, n_pbs->cur, disp_len);            disp_buf[disp_len] = '\0';            break;        }    }    loglog(RC_LOG_SERIOUS, "received and ignored informational message");    return STF_IGNORE;}/* message digest allocation and deallocation */static struct msg_digest *md_pool = NULL;/* free_md_pool is only used to avoid leak reports */voidfree_md_pool(void){    for (;;)    {	struct msg_digest *md = md_pool;	if (md == NULL)	    break;	passert(md_pool != md->next);	md_pool = md->next;	pfree(md);    }}struct msg_digest *alloc_md(void){    struct msg_digest *md = md_pool;    /* convenient initializer:     * - all pointers NULL     * - .note = NOTHING_WRONG     * - .encrypted = FALSE     */    static const struct msg_digest blank_md;    if (md == NULL)	md = alloc_thing(struct msg_digest, "msg_digest");    else	md_pool = md->next;    *md = blank_md;    md->digest_roof = md->digest;    /* note: although there may be multiple msg_digests at once     * (due to suspended state transitions), there is a single     * global reply_buffer.  It will need to be saved and restored.     */    init_pbs(&md->reply, reply_buffer, sizeof(reply_buffer), "reply packet");    return md;}struct state *looking_for_state = NULL;struct msg_digest *looking_for_md = NULL;voidrelease_md(struct msg_digest *md){    passert(looking_for_md == NULL || md != looking_for_md);    passert(looking_for_state == NULL || md->st != looking_for_state);    freeanychunk(md->raw_packet);    pfreeany(md->packet_pbs.start);    /* make sure we are not creating a loop */    passert(md != md_pool);    md->packet_pbs.start = NULL;    md->next = md_pool;    md_pool = md;}/* wrapper for read_packet and process_packet * * The main purpose of this wrapper is to factor out teardown code * from the many return points in process_packet.  This amounts to * releasing the msg_digest and resetting global variables. * * When processing of a packet is suspended (STF_SUSPEND), * process_packet sets md to NULL to prevent the msg_digest being freed. * Someone else must ensure that msg_digest is freed eventually. * * read_packet is broken out to minimize the lifetime of the * enormous input packet buffer, an auto. */voidcomm_handle(const struct iface_port *ifp){    static struct msg_digest *md;#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)    /* Even though select(2) says that there is a message,     * it might only be a MSG_ERRQUEUE message.  At least     * sometimes that leads to a hanging recvfrom.  To avoid     * what appears to be a kernel bug, check_msg_errqueue     * uses poll(2) and tells us if there is anything for us     * to read.     *     * This is early enough that teardown isn't required:     * just return on failure.     */    if (!check_msg_errqueue(ifp, POLLIN))	return;	/* no normal message to read */#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */    md = alloc_md();    md->iface = ifp;    if (read_packet(md))	process_packet(&md);    if (md != NULL)	release_md(md);    cur_state = NULL;    reset_cur_connection();    cur_from = NULL;}/* read the message. * Since we don't know its size, we read it into * an overly large buffer and then copy it to a * new, properly sized buffer. */static boolread_packet(struct msg_digest *md){    const struct iface_port *ifp = md->iface;    int packet_len;    /* ??? this buffer seems *way* too big */    u_int8_t bigbuffer[MAX_INPUT_UDP_SIZE];#ifdef NAT_TRAVERSAL    u_int8_t *_buffer = bigbuffer;#endif    union    {	struct sockaddr sa;	struct sockaddr_in sa_in4;	struct sockaddr_in6 sa_in6;    } from,to;    int from_len = sizeof(from);    int to_len   = sizeof(to);    err_t from_ugh = NULL;    static const char undisclosed[] = "unknown source";    happy(anyaddr(addrtypeof(&ifp->ip_addr), &md->sender));    zero(&from.sa);    packet_len = recvfromto(ifp->fd, bigbuffer			    , sizeof(bigbuffer), /*flags*/0			    , &from.sa, &from_len			    , &to.sa, &to_len);    /* we do not do anything with *to* addresses yet... we will */    /* First: digest the from address.     * We presume that nothing here disturbs errno.     */    if (packet_len == -1    && from_len == sizeof(from)    && all_zero((const void *)&from.sa, sizeof(from)))    {	/* "from" is untouched -- not set by recvfrom */	from_ugh = undisclosed;    }    else if (from_len    < (int) (offsetof(struct sockaddr, sa_family) + sizeof(from.sa.sa_family)))    {	from_ugh = "truncated";    }    else    {	const struct af_info *afi = aftoinfo(from.sa.sa_family);	if (afi == NULL)	{	    from_ugh = "unexpected Address Family";	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?