int get_source_ipv4(int protocol, struct sockaddr_in * address) { /* Voir la section NOTES du man(2) de gethostname pour la taille * du buffer. */ char buffer[HOST_NAME_MAX+1]; gethostname(buffer, HOST_NAME_MAX+1); int success = get_ipv4(buffer, protocol, address); /* Workaround pour obtenir une adresse de la machine. * * Sur certaines machines getaddrinfo retourne pour unique adresse 127.0.0.1 * lorsqu'on donne le hostname de la machine... * Sur d'autres elle retourne bien les adresses des interfaces * de la machine. * * De même avec les « vrais » ping et traceroute: * `ping localhost` et `ping <hostname de la machine>` vont tous deux se faire sur * 127.0.0.1, mais sur d'autres machines se feront sur deux adresses différentes. * Configuration des machines ? Versions des logiciels ? ...? * * Avec ça, ça fonctionne partout : */ const in_addr_t REFUSED_IPV4 = inet_addr("127.0.0.1"); if (address->sin_addr.s_addr == REFUSED_IPV4) success = get_interface_ipv4(address); return success; }
int pf_block_probe(char *incoming_ip, int portnum, struct opt *opts) { struct pfioc_rule pr; struct pfioc_pooladdr paddr; struct sockaddr ifr; char curr_ipv4[16]; char *ifname = opts->ifname; short test_result = 0; int pf_dev_fd, ret = 1, sockfd; static int num_rules_added = 0; /* the rule number to add the next rule after */ memset(&pr, 0, sizeof(struct pfioc_rule)); memset(&pr.rule, 0, sizeof(struct pf_rule)); memset(&paddr, 0, sizeof(struct pfioc_pooladdr)); if((sockfd = get_dgram_socket()) < 0) { (void)logmsg("get_dgram_socket() no socket for getipv4()"); (void)report_status_and_bail(BAIL_OUT, errno); } if(! (get_interface_ipv4(sockfd, ifname, &ifr, curr_ipv4))) { (void)logmsg("Unable to obtain ipv4 for interface %s\n", ifname); (void)close(sockfd); (void)report_status_and_bail(BAIL_OUT, errno); } else (void)close(sockfd); /* init rule structure */ pr.rule.action = PF_DROP; pr.rule.quick = 1; pr.rule.log = 1; pr.rule.af = AF_INET; pr.rule.proto = IPPROTO_TCP; pr.rule.src.addr.type = PF_ADDR_ADDRMASK; memset(&pr.rule.src.addr.v.a.mask.v4, 255, 4); /* match only this host:port */ inet_pton(AF_INET, incoming_ip, &pr.rule.src.addr.v.a.addr.v4); pr.rule.src.addr.type = PF_ADDR_ADDRMASK; memset(&pr.rule.dst.addr.v.a.mask.v4, 255, 4); inet_pton(AF_INET, curr_ipv4, &pr.rule.dst.addr.v.a.addr.v4); pr.rule.dst.port_op = PF_OP_EQ; pr.rule.keep_state = 0; pr.rule.flags = TH_SYN; pr.rule.flagset = (TH_SYN | TH_ACK | TH_FIN | TH_RST); pr.rule.dst.port[0] = htons(portnum); pf_dev_fd = open("/dev/pf", O_RDWR); if(pf_dev_fd < 0) { (void)logmsg("failed to open /dev/pf, *not* adding rule\n"); (void)logmsg("connection attempt from %s on port %d _NOT_ BLOCKED\n", incoming_ip, portnum); (void)report_status_and_bail(DO_NOT_BAIL, errno); (void)close(pf_dev_fd); ret = 0; } /* check the rule doesn't already exist in rules added so far */ if(ret) test_result = test_rule(incoming_ip, &pf_dev_fd, portnum, num_rules_added, opts->flags); if(test_result && ret) { if((ioctl(pf_dev_fd, DIOCBEGINADDRS, &paddr)) < 0) logmsg("err: ioctl DIOCBEGINADDRS"); pr.action = PF_CHANGE_GET_TICKET; pr.pool_ticket = paddr.ticket; if((ioctl(pf_dev_fd, DIOCCHANGERULE, &pr)) < 0) logmsg("err: ioctl DIOCCHANGERULE"); pr.action = PF_CHANGE_ADD_AFTER; pr.nr = num_rules_added; if((ioctl(pf_dev_fd, DIOCCHANGERULE, &pr)) < 0) logmsg("err: ioctl DIOCCHANGERULE"); num_rules_added++; /* static */ (void)logmsg("added blocking filter rule for remote host %s on port %d", incoming_ip, portnum); } else if(test_result == 0) /* some moron may attempt to fill up the log file! * this *may* become an issue during testing. * Here, a zero tolerance response could be taken * for repeat offenders; for now, just ignore and log */ (void)logmsg("rule already exists, ignoring"); else { (void)logmsg("connection %s on port %d", incoming_ip, portnum); (void)logmsg("ioctl: error searching current ruleset - *no* rule added"); } (void)close(pf_dev_fd); return ret; }