⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ha.c

📁 mobile ip 在linux下的一种实现
💻 C
📖 第 1 页 / 共 5 页
字号:
				found = 1;				break;			}		}		if (!found && from_iface != NULL)			reply->ha_addr.s_addr = from_iface->addr.s_addr;	}	memcpy(reply->id, ext->req->id, REG_REQ_ID_LEN);	if (mn_spi) {		if (mn_spi->replay_method == REPLAY_PROTECTION_TIMESTAMP &&		    code == REGREP_ID_MISMATCH_HA) {			reply->id[0] = htonl(time(NULL) + UNIX_NTP_DIFF);		} else if (mn_spi->replay_method == REPLAY_PROTECTION_NONCE) {			reply->id[0] = get_rand32();			if (nonce != NULL)				*nonce = reply->id[0];		}	}	msgpos += sizeof(struct reg_rep);	left -= sizeof(struct reg_rep);	n = ha_add_ext_start(msg, msgpos, left, ext, 0, mn_spi, NULL,			     auth_type);	if (n < 0)		return -1;	msgpos += n;	left -= n;	n = ha_add_ext_end(msg, msgpos, sock_addr->sin_addr, left, ext);	if (n < 0)		return -1;	msgpos += n;	left -= n;	msglen = msgpos - msg;	if (forced_iface != NULL &&	    setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, forced_iface->dev,		       IFNAMSIZ)) {		DEBUG(DEBUG_FLAG, "setsockopt(SOL_SOCKET, SO_BINDTODEVICE): "		      "%s\n", strerror(errno));	}	DEBUG(DEBUG_FLAG, "send_reg_failure(code=%i): "	      "sending %i bytes to %s:%i (forced_iface=%s)\n", code, msglen,	      inet_ntoa(sock_addr->sin_addr), ntohs(sock_addr->sin_port),	      forced_iface != NULL ? forced_iface->dev : "N/A");	result = sendto(s, msg, msglen, 0,			(struct sockaddr *)sock_addr,			sizeof(struct sockaddr_in));	if (forced_iface != NULL) {		/* kernel seems to require optlen >= sizeof(int); in addition,		 * 2.2 kernels seem to report error (Invalid argument) even		 * when this unbinding success.. */		char dummy[sizeof(int)];		memset(dummy, 0, sizeof(dummy));		if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, dummy,			       sizeof(dummy)) < 0 &&		    setsockopt(s, SOL_PACKET, SO_BINDTODEVICE, NULL, 0) < 0)			DEBUG(DEBUG_FLAG, "setsockopt(SOL_SOCKET, "			      "SO_BINDTODEVICE): %s (this is probably "			      "bogus)\n", strerror(errno));	}	return dynamics_check_sendto(result, msglen, "send_reg_failure");}/** * handle_reg_msg: * @s: registration message socket (UDP) * * Processes a registration request message that has arrived on socket @s. * * Returns: *   0 on success or -1 on failure */static inthandle_reg_msg(struct interface_entry *from_iface, int s){	char msg[MAXMSG];	struct sockaddr_in cli_addr;	struct in_addr dst_addr;	struct msghdr mh;	char cdata[256];	struct iovec iov;	struct cmsghdr *cmsg;	struct bindingentry *binding;	struct spi_entry *mn_spi;	int n, res, rsock;	struct msg_extensions ext;	int killbinding;	int code, auth_type;	char mn_addrstr[17];	char fa_addrstr[17];	struct ha_tunnel_data *t_data = NULL;	struct bindingkey bkey;	struct node *node;	struct interface_entry *force_iface = NULL;	memset(&cli_addr, 0, sizeof(cli_addr));	dst_addr.s_addr = 0;	memset(&mh, 0, sizeof(mh));	iov.iov_base = msg;	iov.iov_len = MAXMSG;	mh.msg_name = &cli_addr;	mh.msg_namelen = sizeof(cli_addr);	mh.msg_iov = &iov;	mh.msg_iovlen = 1;	mh.msg_control = &cdata;	mh.msg_controllen = sizeof(cdata);	n = recvmsg(s, &mh, 0);	DEBUG(DEBUG_FLAG, "Received %d bytes from %s:%d\n", n,	      inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));	if (n < 0) {		LOG2(LOG_ERR, "handle_reg_msg - recvfrom failed - %s\n",		     strerror(errno));		return -1;	}	for (cmsg = CMSG_FIRSTHDR(&mh); cmsg != NULL;	     cmsg = DYNAMICS_CMSG_NXTHDR(&mh, cmsg)) {		if (cmsg->cmsg_level == SOL_IP &&		    cmsg->cmsg_type == IP_PKTINFO) {			struct _in_pktinfo *pkt;			pkt = (struct _in_pktinfo *) CMSG_DATA(cmsg);			dst_addr = pkt->ipi_addr;			DEBUG(DEBUG_FLAG, "\tIP_PKTINFO: ipi_ifindex=%i "			      "ipi_spec_dst=%s ", pkt->ipi_ifindex,			      inet_ntoa(pkt->ipi_spec_dst));			DEBUG(DEBUG_FLAG, "ipi_addr=%s\n",			      inet_ntoa(pkt->ipi_addr));		}	}	/* use the matching UDP socket for the registration reply */	rsock = -1;	for (node = list_get_first(&config.interfaces); node != NULL;	     node = list_get_next(node)) {		struct interface_entry *iface =			(struct interface_entry *) node;		if (iface->addr.s_addr == dst_addr.s_addr ||			(iface->ha_disc &&			 iface->bcaddr.s_addr == dst_addr.s_addr)) {			rsock = iface->udp_sock;		}	}	if (rsock < 0 && from_iface != NULL &&	    dst_addr.s_addr == (unsigned int) -1) {		DEBUG(DEBUG_FLAG, "Broadcast 255.255.255.255 destination - "		      "using interface[%s] UDP socket[%i]\n", from_iface->dev,		      from_iface->udp_sock);		rsock = from_iface->udp_sock;	}	if (rsock < 0) {		LOG2(LOG_WARNING, "Could not find UDP socket for "		     "registration reply - trying recv. socket\n");		rsock = s;	}	res = parse_msg(msg, n, &ext);	if (ext.req != NULL && ntohs(ext.req->lifetime) == 0 &&	    ext.req->home_addr.s_addr == cli_addr.sin_addr.s_addr &&	    ext.req->home_addr.s_addr == ext.req->co_addr.s_addr) {		/* RFC 2002, Ch. 3.8.3.1:		 * When HA is replying to deregistration (lifetime == 0 &&		 * COA == home addr) whose srcIP is MN's home address, the		 * reply must be send directly to home network bypassing any		 * mobility bindings */		DEBUG(DEBUG_FLAG, "Dereg. from home => bypassing mobility "		      "bindings in routing\n");		force_iface = from_iface;	}	if (res == -3 || res == -4) {		LOG2(LOG_WARNING, "Unknown critical vendor extension in a "		     "request from %s:%i\n", inet_ntoa(cli_addr.sin_addr),		     ntohs(cli_addr.sin_port));		send_reg_failure(rsock, &cli_addr, NULL, 0,				 res == -3 ? REGREP_UNSUPP_VENDOR_ID_MN_HA :				 REGREP_UNSUPP_VENDOR_ID_FA_HA, NULL, &ext,				 force_iface, NULL, from_iface);		stats.discarded_vendor_ext++;		report_discarded_msg(msg, n, &cli_addr,				     "unknown vendor extension");		return -1;	} else if (res != 0 || ext.req == NULL) {		char *reason = "N/A";		if (res == -1) {			reason = "unknown extension";			stats.discarded_unknown_ext++;		} else if (res == -2) {			reason = "malformed message";			stats.discarded_malformed_msg++;		} else if (ext.req == NULL) {			reason = "not a request";			stats.discarded_not_request++;		}		LOG2(LOG_WARNING, "Message parser failed or not a request "		     "(from %s:%i): %s\n", inet_ntoa(cli_addr.sin_addr),		     ntohs(cli_addr.sin_port), reason);		report_discarded_msg(msg, n, &cli_addr, reason);		return -1;	}	memcpy(&bkey.mn_addr, &ext.req->home_addr, sizeof(bkey.mn_addr));	bkey.ha_addr = config.sha_addr.s_addr != 0 ? config.sha_addr :		ext.req->ha_addr;	bkey.priv_ha = config.priv_ha;	binding = binding_fetch(bindings, &bkey);	if (binding != NULL)		t_data = (struct ha_tunnel_data *) binding->data;	mn_spi = validate_request(binding, cli_addr.sin_addr, msg, n, &ext,				  &code, &auth_type);	if (code > 2) {		send_reg_failure(rsock, &cli_addr, mn_spi, 0, code,				 (t_data != NULL ? &t_data->nonce : NULL),				 &ext, force_iface, binding, from_iface);		stats.req_rejected++;		report_discarded_msg(msg, n, &cli_addr, "invalid message");		return -1;	}	if (mn_spi == NULL) {		stats.req_rejected++;		report_discarded_msg(msg, n, &cli_addr, "MN SPI not found");		return -1;	}	dynamics_strlcpy(mn_addrstr, inet_ntoa(ext.req->home_addr),			 sizeof(mn_addrstr));	dynamics_strlcpy(fa_addrstr, inet_ntoa(ext.req->co_addr),			 sizeof(fa_addrstr));	if (binding != NULL) {		t_data->auth_type = (auth_type == AUTH_MAC_RFC2002 ?				     AUTH_RFC2002BIS : AUTH_RFC2002);		/* If the id field is identical the message was a duplicate.		 * In order to avoid breaking the tunnel drop this message as		 * a special case without sending a failure reply if the replay		 * protection is used		 */		if (mn_spi->replay_method != REPLAY_PROTECTION_NONE &&		    binding->id[0] == ext.req->id[0] &&		    binding->id[1] == ext.req->id[1]) {			DEBUG(DEBUG_FLAG,			      "Received duplicate request - dropping it\n");			stats.req_rejected++;			return -1;		}		/* Make sure that the id field is incremented if the timestamp		 * protection is used */		if (mn_spi->replay_method == REPLAY_PROTECTION_TIMESTAMP &&		    (ntohl(binding->id[0]) > ntohl(ext.req->id[0]) ||		     (ntohl(binding->id[0]) == ntohl(ext.req->id[0]) &&		      ntohl(binding->id[1]) >= ntohl(ext.req->id[1])))) {			LOG2(LOG_NOTICE, "Timestamp did not increase "			     "(MN=%s, FA=%s)\n", mn_addrstr, fa_addrstr);			send_reg_failure(rsock, &cli_addr, mn_spi,					 t_data->auth_type,					 REGREP_ID_MISMATCH_HA,					 &t_data->nonce, &ext, force_iface,					 binding, from_iface);			stats.req_rejected++;			return -1;		}		/* remove binding from list (does not remove tunnels etc.) */		binding_remove(binding);	} else {		LOG2(LOG_NOTICE, "MN %s registers, FA is %s\n", 		     mn_addrstr, fa_addrstr);	}	stats.req_accepted++;	killbinding = 0;	if (binding &&	    (binding->lower_addr.s_addr != (config.sha_addr.s_addr != 0 ?					    config.sha_addr.s_addr :					    ext.req->co_addr.s_addr) ||	     ext.req->lifetime == 0)) {		DEBUG(DEBUG_FLAG, "Found existing binding for MN %s\n",		      mn_addrstr);		if (ext.req->co_addr.s_addr == ext.req->home_addr.s_addr &&		    ext.req->lifetime == 0) {			DEBUG(DEBUG_FLAG, "MN is deregistering all its "			      "simultaneous bindings\n");			/* Note: RFC 2002, 3.6.1.2, special case			 * This should be taken into account if the			 * simultaneous bindings are implemented.			 * At the moment we just deregister the only possible			 * binding below. */		}#ifdef USE_TEARDOWN		/* if co_addr differs in request, send reply to old		 * co_addr to purge old tunnel segment */		if (config.sha_addr.s_addr == 0 &&		    binding->lower_addr.s_addr != ext.req->co_addr.s_addr) {			binding->timeout = 0;			DEBUG(DEBUG_FLAG, "Sending purge msg to %s\n",			      inet_ntoa(binding->lower_addr));			send_reg_repl(s, binding, mn_spi, NULL, force_iface,				      REGREP_ACCEPTED);		}#endif		if (ext.req->lifetime > 0) {			/* it was a location update */			LOG2(LOG_INFO, "MN %s updating tunnel to FA %s\n", 			     mn_addrstr, fa_addrstr);			if (switch_tunnel(binding, &ext, mn_spi) < 0)				return -1;		} else {			/* if it is a deregistration request,			 * destroy the binding after the reply is sent,			 * since the binding is needed when sending the			 * reply */			LOG2(LOG_NOTICE, "MN %s deregisters\n", mn_addrstr);			remove_tunnel(binding);			if (cli_addr.sin_addr.s_addr == binding->mn_addr.s_addr			    && ext.req->co_addr.s_addr ==			    ext.req->home_addr.s_addr) {				DEBUG(DEBUG_FLAG, "MN returned home and "				      "deregistered all care-of addresses\n");				/* FIX: also HA should send gratuitous ARP				 * telling that MN takes care of its own				 * packets from now on;				 * draft-ietf-mobileip-rfc2002-bis-03.txt, 4.6;				 * This would require that HA would get the				 * link-layer address of the MN from the				 * deregistration message and use it in the				 * gratuitous ARP packet */			}			killbinding = 1;		}	} 	if (binding == NULL) {		if (ntohs(ext.req->lifetime) == 0) {			DEBUG(DEBUG_FLAG, "Deregistration attempt, but binding"			      " not found - creating temporary binding\n");			binding = create_binding(&ext, mn_spi, 0);			killbinding = 1;		} else {			binding = create_binding(&ext, mn_spi, 1);		}		if (binding == NULL) {			LOG2(LOG_ERR, "Failed to create binding for MN: %s, "			     "FA: %s\n", mn_addrstr, fa_addrstr);			send_reg_failure(rsock, &cli_addr, mn_spi,					 (auth_type == AUTH_MAC_RFC2002 ?					  1 : 0),					 REGREP_NO_RESOURCES_HA, NULL, &ext,					 force_iface, binding, from_iface);			return -1;		}		t_data = (struct ha_tunnel_data *) binding->data;		t_data->auth_type = (auth_type == AUTH_MAC_RFC2002 ?				     AUTH_RFC2002BIS : AUTH_RFC2002);	}	ASSERT(binding != NULL);	t_data = (struct ha_tunnel_data *) binding->data;	ASSERT(t_data != NULL);	binding->mod_time = time(NULL);	t_data->reverse_tunnel = (ext.req->opts & REGREQ_REVERSE_TUNNEL) != 0;	if (ext.req->opts & REGREQ_MINIMAL_ENCAPS)		t_data->encapsulation = ENCAPS_MINIMAL;	else if (ext.req->opts & REGREQ_GRE_ENCAPS)		t_data->encapsulation = ENCAPS_GRE;	else		t_data->encapsulation = ENCAPS_IPIP;	if (ext.fa_keyreq)		binding->fa_spi = ntohl(ext.fa_keyreq->spi);	else		binding->fa_spi = 0;	/* If the request has a public key add it to the binding */	if (ext.fa_pubkey) {		/* binding->fa_pubkey is NULL if we have generated a		 * new SK. If the public key sent by the FA is the same 		 * as in a previous binding, we can reuse the encrypted		 * SK and save some CPU cycles */		if (binding->fa_pubkey &&		    binding->last_sent_fa_pubkeyrep != NULL &&		    (memcmp(binding->fa_pubkey, 			    ext.fa_pubkey, 			    GET_KEY_EXT_LEN(ext.fa_pubkey)) == 0))		{			DEBUG(DEBUG_FLAG, "Reusing encrypted SK for FA %s\n",			      fa_addrstr);		} else {			if (binding->fa_pubkey)				free(binding->fa_pubkey);			if (binding->last_sent_fa_pubkeyrep)				free(binding->last_sent_fa_pubkeyrep);			binding->last_sent_fa_pubkeyrep = NULL;			binding->fa_pubkey = (struct msg_key *)				malloc(GET_KEY_EXT_LEN(ext.fa_pubkey));			if (binding->fa_pubkey != NULL) {				memcpy(binding->fa_pubkey, ext.fa_pubkey,				       GET_KEY_EXT_LEN(ext.fa_pubkey));			} else {				LOG2(LOG_ERR, "Not enough memory "				     "for fa_pubkey\n");				return -1;			}			binding->last_sent_fa_pubkeyrep =				dynamics_do_rsa_encrypt(binding->key,							binding->keylen,							binding->fa_pubkey);			if (binding->last_sent_fa_pubkeyrep == NULL) {				LOG2(LOG_ERR, "RSA encryption failed (MN=%s, "				     "FA=%s)\n", mn_addrstr, fa_addrstr);			}		}	} else {		/* remove the (possible) old FA pubkey from the binding to make		 * sure that the next FA using RSA will get the correct key */		if (binding->fa_pubkey)			free(binding->fa_pubkey);		binding->fa_pubkey = NULL;		if (binding->last_sent_fa_pubkeyrep)			free(binding->last_sent_fa_pubkeyrep);		binding->last_sent_fa_pubkeyrep = NULL;	}	memcpy(&binding->id, ext.req->id, REG_REQ_ID_LEN)

⌨️ 快捷键说明

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