📄 server.c
字号:
log_errno((e, "setsockopt IPSEC_POLICY in process_raw_ifaces()")); close(fd); return -1; } policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; if (setsockopt(fd, level, opt , &policy, sizeof(policy)) < 0) { log_errno((e, "setsockopt IPSEC_POLICY in process_raw_ifaces()")); close(fd); return -1; } }#endif setportof(htons(port), &ifp->addr); if (bind(fd, sockaddrof(&ifp->addr), sockaddrlenof(&ifp->addr)) < 0) { log_errno((e, "bind() for %s/%s %s:%u in process_raw_ifaces()" , ifp->name, v_name , ip_str(&ifp->addr), (unsigned) port)); close(fd); return -1; } setportof(htons(pluto_port), &ifp->addr); return fd;}static voidprocess_raw_ifaces(struct raw_iface *rifaces){ struct raw_iface *ifp; /* Find all virtual/real interface pairs. * For each real interface... */ for (ifp = rifaces; ifp != NULL; ifp = ifp->next) { struct raw_iface *v = NULL; /* matching ipsecX interface */ struct raw_iface fake_v; bool after = FALSE; /* has vfp passed ifp on the list? */ bool bad = FALSE; struct raw_iface *vfp; /* ignore if virtual (ipsec*) interface */ if (strncmp(ifp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX)-1) == 0) continue; for (vfp = rifaces; vfp != NULL; vfp = vfp->next) { if (vfp == ifp) { after = TRUE; } else if (sameaddr(&ifp->addr, &vfp->addr)) { /* Different entries with matching IP addresses. * Many interesting cases. */ if (strncmp(vfp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX)-1) == 0) { if (v != NULL) { loglog(RC_LOG_SERIOUS , "ipsec interfaces %s and %s share same address %s" , v->name, vfp->name, ip_str(&ifp->addr)); bad = TRUE; } else { v = vfp; /* current winner */ } } else { /* ugh: a second real interface with the same IP address * "after" allows us to avoid double reporting. */#if defined(linux) && defined(KERNEL26_SUPPORT) if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) { if (after) { bad = TRUE; break; } continue; }#endif if (after) { loglog(RC_LOG_SERIOUS , "IP interfaces %s and %s share address %s!" , ifp->name, vfp->name, ip_str(&ifp->addr)); } bad = TRUE; } } } if (bad) continue;#if defined(linux) && defined(KERNEL26_SUPPORT) if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) { v = ifp; goto add_entry; }#endif /* what if we didn't find a virtual interface? */ if (v == NULL) { if (no_klips) { /* kludge for testing: invent a virtual device */ static const char fvp[] = "virtual"; fake_v = *ifp; passert(sizeof(fake_v.name) > sizeof(fvp)); strcpy(fake_v.name, fvp); addrtot(&ifp->addr, 0, fake_v.name + sizeof(fvp) - 1 , sizeof(fake_v.name) - (sizeof(fvp) - 1)); v = &fake_v; } else { DBG(DBG_CONTROL, DBG_log("IP interface %s %s has no matching ipsec* interface -- ignored" , ifp->name, ip_str(&ifp->addr))); continue; } } /* We've got all we need; see if this is a new thing: * search old interfaces list. */#if defined(linux) && defined(KERNEL26_SUPPORT)add_entry:#endif { struct iface **p = &interfaces; for (;;) { struct iface *q = *p; /* search is over if at end of list */ if (q == NULL) { /* matches nothing -- create a new entry */ int fd = create_socket(ifp, v->name, pluto_port); if (fd < 0) break;#ifdef NAT_TRAVERSAL if (nat_traversal_support_non_ike && addrtypeof(&ifp->addr) == AF_INET) { nat_traversal_espinudp_socket(fd, "IPv4", ESPINUDP_WITH_NON_IKE); }#endif q = alloc_thing(struct iface, "struct iface"); q->rname = clone_str(ifp->name, "real device name"); q->vname = clone_str(v->name, "virtual device name"); q->addr = ifp->addr; q->fd = fd; q->next = interfaces; q->change = IFN_ADD; interfaces = q; openswan_log("adding interface %s/%s %s" , q->vname, q->rname, ip_str(&q->addr));#ifdef NAT_TRAVERSAL if (nat_traversal_support_port_floating && addrtypeof(&ifp->addr) == AF_INET) { fd = create_socket(ifp, v->name, NAT_T_IKE_FLOAT_PORT); if (fd < 0) break; nat_traversal_espinudp_socket(fd, "IPv4" , ESPINUDP_WITH_NON_ESP); q = alloc_thing(struct iface, "struct iface"); q->rname = clone_str(ifp->name, "real device name"); q->vname = clone_str(v->name, "virtual device name"); q->addr = ifp->addr; setportof(htons(NAT_T_IKE_FLOAT_PORT), &q->addr); q->fd = fd; q->next = interfaces; q->change = IFN_ADD; q->ike_float = TRUE; interfaces = q; openswan_log("adding interface %s/%s %s:%d", q->vname, q->rname, ip_str(&q->addr), NAT_T_IKE_FLOAT_PORT); }#endif break; } /* search over if matching old entry found */ if (streq(q->rname, ifp->name) && streq(q->vname, v->name) && sameaddr(&q->addr, &ifp->addr)) { /* matches -- rejuvinate old entry */ q->change = IFN_KEEP;#ifdef NAT_TRAVERSAL /* look for other interfaces to keep (due to NAT-T) */ for (q = q->next ; q ; q = q->next) { if (streq(q->rname, ifp->name) && streq(q->vname, v->name) && sameaddr(&q->addr, &ifp->addr)) { q->change = IFN_KEEP; } }#endif break; } /* try again */ p = &q->next; } /* for (;;) */ } } /* delete the raw interfaces list */ while (rifaces != NULL) { struct raw_iface *t = rifaces; rifaces = t->next; pfree(t); }}voidfind_ifaces(void){ mark_ifaces_dead(); process_raw_ifaces(find_raw_ifaces4()); process_raw_ifaces(find_raw_ifaces6()); free_dead_ifaces(); /* ditch remaining old entries */ if (interfaces == NULL) loglog(RC_LOG_SERIOUS, "no public interfaces found");}voidshow_ifaces_status(void){ struct iface *p; for (p = interfaces; p != NULL; p = p->next) whack_log(RC_COMMENT, "interface %s/%s %s" , p->vname, p->rname, ip_str(&p->addr));}voidshow_debug_status(void){#ifdef DEBUG whack_log(RC_COMMENT, "debug %s" , bitnamesof(debug_bit_names, cur_debugging));#endif}static volatile sig_atomic_t sighupflag = FALSE;static voidhuphandler(int sig UNUSED){ sighupflag = TRUE;}static volatile sig_atomic_t sigtermflag = FALSE;static voidtermhandler(int sig UNUSED){ sigtermflag = TRUE;}static volatile sig_atomic_t sigchildflag = FALSE;static voidchildhandler(int sig UNUSED){ sigchildflag = TRUE;}/* perform wait4() on all children */static voidreapchildren(void){ pid_t child; int status; struct rusage r; sigchildflag = FALSE; while((child = wait3(&status, WNOHANG, &r)) != 0) { /* got a child to reap */ if(adns_reapchild(child, status)) continue; if(pluto_crypt_handle_dead_child(child, status)) continue; openswan_log("child pid=%d (status=%d) is not my child!", child, status); }}/* call_server listens for incoming ISAKMP packets and Whack messages, * and handles timer events. */voidcall_server(void){ struct iface *ifp; /* catch SIGHUP and SIGTERM */ { int r; struct sigaction act; act.sa_handler = &huphandler; sigemptyset(&act.sa_mask); act.sa_flags = 0; /* no SA_ONESHOT, no SA_RESTART, no nothing */ r = sigaction(SIGHUP, &act, NULL); passert(r == 0); act.sa_handler = &termhandler; r = sigaction(SIGTERM, &act, NULL); passert(r == 0); act.sa_handler = &childhandler; act.sa_flags = SA_RESTART; r = sigaction(SIGCHLD, &act, NULL); passert(r == 0); } for (;;) { fd_set readfds; fd_set writefds; int ndes; /* wait for next interesting thing */ for (;;) { long next_time = next_event(); /* time to any pending timer event */ int maxfd = ctl_fd; if (sigtermflag) exit_pluto(0); if (sighupflag) { /* Ignorant folks think poking any daemon with SIGHUP * is polite. We catch it and tell them otherwise. * There is one use: unsticking a hung recvfrom. * This sticking happens sometimes -- kernel bug? */ sighupflag = FALSE; openswan_log("Pluto ignores SIGHUP -- perhaps you want \"whack --listen\""); } if(sigchildflag) { reapchildren(); } FD_ZERO(&readfds); FD_ZERO(&writefds); FD_SET(ctl_fd, &readfds);#ifdef IPSECPOLICY FD_SET(info_fd, &readfds); if (maxfd < info_fd) maxfd = info_fd;#endif /* the only write file-descriptor of interest */ if (adns_qfd != NULL_FD && unsent_ADNS_queries) { if (maxfd < adns_qfd) maxfd = adns_qfd; FD_SET(adns_qfd, &writefds); } if (adns_afd != NULL_FD) { if (maxfd < adns_afd) maxfd = adns_afd; FD_SET(adns_afd, &readfds); }#ifdef KLIPS if (!no_klips) { int fd = *kernel_ops->async_fdp; if (kernel_ops->process_queue) kernel_ops->process_queue(); if (maxfd < fd) maxfd = fd; passert(!FD_ISSET(fd, &readfds)); FD_SET(fd, &readfds); }#endif if (listening) { for (ifp = interfaces; ifp != NULL; ifp = ifp->next) { if (maxfd < ifp->fd) maxfd = ifp->fd; passert(!FD_ISSET(ifp->fd, &readfds)); FD_SET(ifp->fd, &readfds); } } /* see if helpers need attention */ pluto_crypto_helper_sockets(&readfds); if (no_retransmits || next_time < 0) { /* select without timer */ ndes = select(maxfd + 1, &readfds, &writefds, NULL, NULL); } else if (next_time == 0) { /* timer without select: there is a timer event pending, * and it should fire now so don't bother to do the select. */ ndes = 0; /* signify timer expiration */ } else { /* select with timer */ struct timeval tm; tm.tv_sec = next_time; tm.tv_usec = 0; ndes = select(maxfd + 1, &readfds, &writefds, NULL, &tm); } if (ndes != -1) break; /* success */ if (errno != EINTR) exit_log_errno((e, "select() failed in call_server()")); /* retry if terminated by signal */ } /* figure out what is interesting */ if (ndes == 0) { /* timer event */ if(!no_retransmits) { DBG(DBG_CONTROL, DBG_log(BLANK_FORMAT); DBG_log("*time to handle event")); handle_timer_event(); passert(GLOBALS_ARE_RESET()); } } else { /* at least one file descriptor is ready */ if (adns_qfd != NULL_FD && FD_ISSET(adns_qfd, &writefds)) { passert(ndes > 0); send_unsent_ADNS_queries(); passert(GLOBALS_ARE_RESET()); ndes--; } if (adns_afd != NULL_FD && FD_ISSET(adns_afd, &readfds)) { passert(ndes > 0); DBG(DBG_CONTROL, DBG_log(BLANK_FORMAT); DBG_log("*received adns message")); handle_adns_answer(); passert(GLOBALS_ARE_RESET()); ndes--; }#ifdef KLIPS if (!no_klips && FD_ISSET(*kernel_ops->async_fdp, &readfds)) { passert(ndes > 0); DBG(DBG_CONTROL, DBG_log(BLANK_FORMAT); DBG_log("*received kernel message")); kernel_ops->process_msg(); passert(GLOBALS_ARE_RESET()); ndes--; }#endif for (ifp = interfaces; ifp != NULL; ifp = ifp->next) { if (FD_ISSET(ifp->fd, &readfds)) { /* comm_handle will print DBG_CONTROL intro, * with more info than we have here. */ passert(ndes > 0); comm_handle(ifp); passert(GLOBALS_ARE_RESET()); ndes--; } } if (FD_ISSET(ctl_fd, &readfds)) { passert(ndes > 0); DBG(DBG_CONTROL, DBG_log(BLANK_FORMAT); DBG_log("*received whack message")); whack_handle(ctl_fd); passert(GLOBALS_ARE_RESET()); ndes--; }#ifdef IPSECPOLICY if (FD_ISSET(info_fd, &readfds)) { passert(ndes > 0); DBG(DBG_CONTROL, DBG_log(BLANK_FORMAT); DBG_log("*received info message")); info_handle(info_fd); passert(GLOBALS_ARE_RESET()); ndes--; }#endif /* note we process helper things last on purpose */ ndes -= pluto_crypto_helper_ready(&readfds); passert(ndes == 0); } }}/* * Local Variables: * c-basic-offset: 4 * End Variables: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -