📄 fa.c
字号:
break; } api_send(sock, &addr, addrlen, &send_msg);}static voidhandle_errqueue(int s){ char msg[256]; int n; struct sockaddr_in cli_addr; struct msghdr mh; char cdata[256]; struct iovec iov; struct cmsghdr *cmsg; struct dest_unreachable_data unreach; memset(&mh, 0, sizeof(mh)); iov.iov_base = msg; iov.iov_len = sizeof(msg); mh.msg_name = &cli_addr; mh.msg_namelen = sizeof(cli_addr); mh.msg_iov = &iov; mh.msg_iovlen = 1; mh.msg_control = &cdata; for (;;) { struct dynamics_sock_extended_err *err = NULL; memset(&cli_addr, 0, sizeof(cli_addr)); mh.msg_controllen = sizeof(cdata); n = recvmsg(s, &mh, MSG_ERRQUEUE); if (n < 0) break; memset(&unreach, 0, sizeof(unreach)); unreach.port = -1; if (cli_addr.sin_family == AF_INET) { DEBUG(DEBUG_FLAG, "Learned unreachable address from " "msg_name: %s:%i\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port)); unreach.addr.s_addr = cli_addr.sin_addr.s_addr; unreach.port = cli_addr.sin_port; } for (cmsg = CMSG_FIRSTHDR(&mh); cmsg != NULL; cmsg = DYNAMICS_CMSG_NXTHDR(&mh, cmsg)) { if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) { err = (struct dynamics_sock_extended_err *) CMSG_DATA(cmsg); } } if (err == NULL) { DEBUG(DEBUG_FLAG, "Could not get IP_RECVERR data\n"); break; } DEBUG(DEBUG_FLAG, "\tIP_RECVERR: errno=%i origin=%i " "type=%i code=%i pad=%i info=%i data=%i\n", err->ee_errno, err->ee_origin, err->ee_type, err->ee_code, err->ee_pad, err->ee_info, err->ee_data); unreach.code = err->ee_code; if (unreach.port == -1) { /* Older kernels (2.2.x?) seem to give bogus port * entries or do not return address in msg_name, so try * to get the IP address from offender data */ struct sockaddr_in *offender; offender = (struct sockaddr_in *) SO_EE_OFFENDER(err); if (offender == NULL || offender->sin_family != AF_INET) { DEBUG(DEBUG_FLAG, "Could not get offender data\n"); break; } DEBUG(DEBUG_FLAG, "\toffender %s:%i (ignoring bogus " "port)\n", inet_ntoa(offender->sin_addr), ntohs(offender->sin_port)); unreach.addr.s_addr = offender->sin_addr.s_addr; /* offender->sin_port seem to be bogus in 2.2.17 and * zero in 2.4.4, so better ignore it; port number -1 * is handled as a special wildcard later */ } handle_dest_unreach(&unreach); }}/* Rotating L2 data queue of last registration messages */#define L2_QUEUE_LEN 10/* How many bytes to save from each packet; this is the size of the * registration request header. If the message is registration reply, only * first 20 bytes are checked when searching for L2 data. */#define L2_SAVE_UDP_LEN 24struct pending_registration_l2_info { struct packet_from_info info; unsigned char udp_start[L2_SAVE_UDP_LEN];};static struct pending_registration_l2_info l2_info[L2_QUEUE_LEN];static int l2_next_pos = 0;/* Received registration message. Process it. returns: 0 if successful 1 on error (not enough memory)*/static inthandle_reg_msg(struct interface_entry *iface){ char msg[MAXMSG]; int res, n, check_len; struct sockaddr_in from; socklen_t fromlen; struct packet_from_info *info = NULL, tmpinfo; struct msg_extensions ext; memset(&from, 0, sizeof(from)); fromlen = sizeof(from); n = recvfrom(iface->udp_sock, msg, sizeof(msg), 0, (struct sockaddr *) &from, &fromlen); if (n < 0) { DEBUG(DEBUG_FLAG, "handle_reg_msg - recvmsg: (errno=%i) " "%s\n", errno, strerror(errno)); handle_errqueue(iface->udp_sock); return 0; } DEBUG(DEBUG_FLAG, "Received %d bytes from %s:%d\n", n, inet_ntoa(from.sin_addr), ntohs(from.sin_port)); /* search for L2 data from packet socket */ if (n > 0 && msg[0] == REG_REP) check_len = sizeof(struct reg_rep); else check_len = L2_SAVE_UDP_LEN; if (n >= check_len) { int pos = l2_next_pos; for (;;) { if (pos == 0) pos = L2_QUEUE_LEN - 1; else pos--; if (pos == l2_next_pos) break; if (memcmp(msg, &l2_info[pos].udp_start, check_len) == 0) { DEBUG(DEBUG_FLAG, "\tpending L2 data found " "from pos %i\n", pos); info = &l2_info[pos].info; break; } } } if (info == NULL) { DEBUG(DEBUG_FLAG, "\tcould not find pending L2 data - using " "dummy entry\n"); memset(&tmpinfo, 0, sizeof(tmpinfo)); info = &tmpinfo; info->iface = iface; memcpy(&info->src, &from, sizeof(info->src)); } res = parse_msg(msg, n, &ext); if (res != 0) { 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 (res == -3 || res == -4 || res == -5) { reason = "unknown vendor extension"; stats.discarded_vendor_ext++; } report_discarded_msg(msg, n, &info->src, reason); DEBUG(DEBUG_FLAG, "parse_msg returned %i\n", res); if (res == -3 || res == -4) { DEBUG(DEBUG_FLAG, "Unknown critical vendor extension -" " sending failure reply\n"); send_failure_reply(REGREP_UNSUPP_VENDOR_ID_MN_FA, &ext, info, NULL, 0); } if (res != -5 || ext.rep == NULL) { return 0; } /* let registration replies with unknown CVSE pass through to * be denied properly in handle_reply() */ } if (ext.req && iface->type == INTERFACE_TYPE_UP) { DEBUG(DEBUG_FLAG, "Received registration request from " "interface type UP - rejecting\n"); report_discarded_msg(msg, n, &info->src, "registration request from UP interface"); send_failure_reply(REGREP_ADMIN_PROHIBITED_FA, &ext, info, NULL, 0); } else if (ext.rep && iface->type == INTERFACE_TYPE_DOWN) { DEBUG(DEBUG_FLAG, "Received registration reply from " "interface type DOWN - rejecting\n"); report_discarded_msg(msg, n, &info->src, "registration reply " "from DOWN interface"); } else if (ext.req) { res = handle_request(&ext, info, config); if (res) { stats.req_rejected++; report_discarded_msg(msg, n, &info->src, "registration request rejected"); } else stats.req_accepted++; info_send(FA_INFO_REQUEST, res == 0 ? FA_INFO_OK : FA_INFO_FAILED, ext.req, sizeof(struct reg_req)); } else if (ext.rep) { res = handle_reply(&ext, info); if (res) { stats.rep_rejected++; report_discarded_msg(msg, n, &info->src, "registration reply rejected"); } else stats.rep_accepted++; info_send(FA_INFO_REPLY, res == 0 ? FA_INFO_OK : FA_INFO_FAILED, ext.rep, sizeof(struct reg_rep)); } else if (ext.fa_req) { res = handle_fa_req(msg, n, &ext, &info->src, iface); } else if (ext.fa_rep) { res = handle_fa_rep(msg, n, &ext, &info->src, iface); } else { DEBUG(DEBUG_FLAG, "Unknown registration message type\n"); } return 0;}static inthandle_reg_msg_packet(struct interface_entry *iface){ char msg[MAXMSG]; int n, i; socklen_t fromlen; struct packet_from_info *info; struct iphdr *ip; struct udphdr *udp; int hdrlen = sizeof(struct iphdr) + sizeof(struct udphdr); info = &l2_info[l2_next_pos].info; memset(info, 0, sizeof(*info)); info->iface = iface; fromlen = sizeof(info->from); n = recvfrom(iface->udp_packet, msg, sizeof(msg), 0, (struct sockaddr *) &info->from, &fromlen); if (n < 0) { DEBUG(DEBUG_FLAG, "handle_reg_msg_packet - recvfrom: %s\n", strerror(errno)); return -1; } if (n < hdrlen + L2_SAVE_UDP_LEN) { DEBUG(DEBUG_FLAG, "handle_reg_msg_packet - underflow\n"); return -1; } DEBUG(DEBUG_FLAG, "\treceived %i bytes - saving L2 data to pos %i\n", n, l2_next_pos); DEBUG(DEBUG_FLAG, "\tsll_ifindex=%i sll_hatype=0x%04x sll_pkttype=%i " "sll_halen=%i sll_addr=", info->from.sll_ifindex, ntohs(info->from.sll_hatype), info->from.sll_pkttype, info->from.sll_halen); for (i = 0; i < sizeof(info->from.sll_addr); i++) { if (i > 0) DEBUG(DEBUG_FLAG, ":"); DEBUG(DEBUG_FLAG, "%02x", info->from.sll_addr[i]); } DEBUG(DEBUG_FLAG, "\n"); ip = (struct iphdr *) msg; if (ip->protocol != IPPROTO_UDP) { DEBUG(DEBUG_FLAG, "\tskipping non-UDP packet (protocol=%i)\n", ip->protocol); return -1; } udp = (struct udphdr *) (ip + 1); if (ntohs(udp->dest) != 434) { DEBUG(DEBUG_FLAG, "\tskipping UDP packet to port other than " "434 (%i)\n", ntohs(udp->dest)); return -1; } info->ttl = ip->ttl; info->dst_addr.s_addr = ip->daddr; info->src.sin_family = AF_INET; info->src.sin_addr.s_addr = ip->saddr; info->src.sin_port = udp->source; memcpy(&l2_info[l2_next_pos].udp_start, udp + 1, L2_SAVE_UDP_LEN); l2_next_pos++; if (l2_next_pos >= L2_QUEUE_LEN) l2_next_pos = 0; return 0;}/* Open sockets and initialize them. */static voidinit_sockets(void){ struct interface_entry *iface; int one = 1;#ifdef INCLUDE_IPAY struct in_addr dummy; memset(&dummy, 0, sizeof(dummy)); ipay_sock = dynamics_open_udp_socket(config, dummy, config->ipay_port, NULL); if (ipay_sock < 0) { LOG2(LOG_ALERT, "Ipay socket open failed - %s\n", strerror(errno)); clean_up(-1); }#endif /* Unix sockets for API calls */ api_rw_sock = api_open_socket(config->fa_api_admin_socket_path, config->fa_api_admin_socket_group, config->fa_api_admin_socket_owner, config->fa_api_admin_socket_permissions); if (api_rw_sock < 0) { syslog(LOG_ERR, "init - open_api_rw_socket: %m"); } api_ro_sock = api_open_socket(config->fa_api_read_socket_path, config->fa_api_read_socket_group, config->fa_api_read_socket_owner, config->fa_api_read_socket_permissions); if (api_ro_sock < 0) { syslog(LOG_ERR, "init - open_api_ro_socket: %m"); } /* RAW sockets for ICMP agent solicitation messages */ DEBUG(DEBUG_FLAG, "Initializing interfaces\n"); iface = (struct interface_entry *) list_get_first(&config->interfaces); if (iface == NULL) { LOG2(LOG_ALERT, "No interfaces defined\n"); clean_up(-1); } while (iface != NULL) { DEBUG(DEBUG_FLAG, "\t%s: ", iface->dev); iface->if_index = dyn_ip_get_ifindex(iface->dev); if (iface->if_index < 0) { LOG2(LOG_ALERT, "Could not get ifindex for interface %s\n", iface->dev); clean_up(-1); } DEBUG(DEBUG_FLAG, "ifindex=%i ", iface->if_index); if (iface->type == INTERFACE_TYPE_BOTH || iface->type == INTERFACE_TYPE_UP) up_interface = iface; if (iface->force_addr.s_addr != 0) { DEBUG(DEBUG_FLAG, "forcing address "); iface->addr = iface->force_addr; } else { if (dyn_ip_get_ifaddr(iface->dev, &iface->addr) != 0) { LOG2(LOG_ALERT, "could not get interface[%s] " "address\n", iface->dev); clean_up(-1); } } iface->udp_sock = dynamics_open_udp_socket(config->socket_priority, iface->force_addr, config->udp_port, iface->dev); if (iface->udp_sock < 0) { LOG2(LOG_ALERT, "UDP socket opening failed\n"); clean_up(-1); } if (setsockopt(iface->udp_sock, SOL_IP, IP_RECVERR, (const void *) &one, sizeof(one)) < 0) { DEBUG(DEBUG_FLAG, "init_sockets - setsockopt(SOL_IP, IP_RECVERR): " " %s\n", strerror(errno)); /* continue without IP_RECVERR */ } iface->udp_packet = open_agent_icmp_adv_socket(iface->dev, UDP_FILTER_PORT434); if (iface->udp_packet < 0) { LOG2(LOG_ALERT, "could not open packet socket for " "UDP port 434\n"); clean_up(-1); } iface->icmp_sock = open_agent_icmp_adv_socket(iface->dev, AGENTADV_FILTER_SOL); if (iface->icmp_sock < 0) { LOG2(LOG_ALERT, "could not open ICMP socket\n"); clean_up(-1); } DEBUG(DEBUG_FLAG, "%s => socket=%i\n", inet_ntoa(iface->addr), iface->icmp_sock); iface = (struct interface_entry *) list_get_next(&iface->node); }}/* initializations that are run on all config reads */static voidinit_config_data(void){ int i; /* Configure logging */ openlog("foreign agent", LOG_PID | LOG_CONS, config->syslog_facility); /* Fill in the upper_fa_addr */ upper_fa_addr.sin_family = AF_INET; memcpy(&upper_fa_addr.sin_addr, &config->upper_fa_addr, sizeof(config->upper_fa_addr)); upper_fa_addr.sin_port = htons(config->upper_fa_port); DEBUG(DEBUG_FLAG, "\tinit_data: upper_fa_addr = %s:%d\n", inet_ntoa(upper_fa_addr.sin_addr), ntohs(upper_fa_addr.sin_port)); /* Get the FA public key */ if (rsa_initialize(config->key_file) != 0) { fprintf(stderr, "RSA initialization failed (key file: %s)\n", config->key_file); clean_up(1); } if (fa_public_key != NULL) free(fa_public_key); fa_public_key = (struct msg_key *) malloc(sizeof(struct msg_key) + SPI_LEN + rsa_get_public_key_len() + 1); if (fa_public_key == NULL) { fprintf(stderr, "Not enough memory for fa_public_key\n"); clean_up(1); } if (rsa_get_public_key_len() + SPI_LEN > 255) { fprintf(stderr, "fa_public_key over 255 bytes long - does " "not fit into extension\n"); clean_up(1); } init_key_extension(fa_public_key, VENDOR_EXT_DYNAMICS_FA_PUBKEY, htonl(PUBKEY_ALG_SPI_RSA), rsa_get_public_key_len()); memcpy(MSG_KEY_DATA(fa_public_key), rsa_get_public_key(), GET_KEY_LEN(fa_public_key)); if (fa_nai != NULL) { free(fa_nai); fa_nai = NULL; } if (config->fa_nai[0] != '\0') { fa_nai = (struct fa_nai_ext *) malloc(sizeof(struct fa_nai_ext) + strlen(config->fa_nai)); if (fa_nai == NULL) { DEBUG(DEBUG_FLAG, "Not enough memory for fa_nai\n"); clean_up(1); } fa_nai->type = VENDOR_EXT_TYPE2; fa_nai->reserved = 0; fa_nai->length = sizeof(struct fa_nai_ext) - 2 + strlen(config->fa_nai); fa_nai->vendor_id = htonl(VENDOR_ID_DYNAMICS); fa_nai->sub_type = htons(VENDOR_EXT_DYNAMICS_FA_NAI); memcpy(fa_nai + 1, config->fa_nai, strlen(config->fa_nai)); } last_challenges = (struct challenge_ext **) malloc(config->challenge_window * sizeof(struct challenge_ext *)); if (last_challenges == NULL) { DEBUG(DEBUG_FLAG, "Not enough memory for last_challenges\n"); clean_up(1); } for (i = 0; i < config->challenge_window; i++) last_challenges[i] = NULL; last_challenges_pos = 0;}/* initializations that are run only once (not on config reloads) */static voidinit_data(void){ struct interface_entry *iface; iface = (struct interface_entry *) list_get_first(&config->interfaces); if (iface == NULL) { LOG2(LOG_ALERT, "init_data: no interfaces defined\n"); clean_up(1); } allow_ipv4_forwarding(); /* Initialize hashes */ tunnels_hash = tunnel_init(config->tunnel_device, config->routing_table_start, config->routing_table_end); if (tunnels_hash == NULL) { LOG2(LOG_ALERT, "init_data: Tunnels hash not initialized!\n"); clean_up(1); } bindings_hash = binding_init(config->max_bindings, config->fa_default_tunnel_lifetime); if (bindings_hash == NULL) { LOG2(LOG_ALERT, "init_data: Could not initialize" " bindings_hash\n"); clean_up(1); } bcounters.bindingcount = 0; bcounters.pendingcount = 0; if (!fa_hash_init()) { LOG2(LOG_ALERT, "init_data: Could not initialize fa_hash\n"); clean_up(1); } if (mn_addr_init() < 0) { LOG2(LOG_ALERT, "init_data: Could not initialize " "mn_addr_hash\n"); clean_up(1); } DEBUG(DEBUG_FLAG, "\tinit_data: Hashes initialized\n"); iface = (struct interface_entry *) list_get_first(&config->interfaces); srand(time(NULL) ^ (iface ? iface->addr.s_addr : 0)); /* Reset statistic counters */ memset(&stats, 0, sizeof(stats)); dynamics_strlcpy(stats.version, VERSION, sizeof(stats.version)); /* Set up signal actions */ signal(SIGHUP, reload_config); signal(SIGTERM, clean_up); /* clean death */ signal(SIGINT, clean_up); /* clean death */}/* set_expr_timer: * @tv: Set to time when next event is due. * @next_agentadv: Time when next agent advertisement is due. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -