From: Apple Date: Sat, 11 Jun 2016 02:35:45 +0000 (+0000) Subject: network_cmds-511.tar.gz X-Git-Tag: macos-1012^0 X-Git-Url: https://git.saurik.com/apple/network_cmds.git/commitdiff_plain/26c66ce99fcafd17b96b2fc4815ddf9fc3d85feb?ds=inline network_cmds-511.tar.gz --- diff --git a/frame_delay/frame_delay.8 b/frame_delay/frame_delay.8 new file mode 100644 index 0000000..0f454d5 --- /dev/null +++ b/frame_delay/frame_delay.8 @@ -0,0 +1,45 @@ +.Dd October 12, 2015 +.Dt FRAME_DELAY 8 +.Os Darwin +.Sh NAME +.Nm frame_delay +.Nd Utility to measure TCP/UDP frame delay + +.Sh DESCRIPTION +.Pp +The +.Nm +utility is designed to measure the effect of latency on +delivery of evenly spaced TCP/UDP frames. This can be latency induced +due to buffering or protocol stack or network drivers. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl m +Server/Client mode. Should be "server" or "client". +.It Fl t +TCP/UDP frame. Should be either "tcp" or "udp". +.It Fl i +(Client Only) Server ip address. +.It Fl p +Port number. +.It Fl n +Number of frames. +.It Fl f +Frame size. +.It Fl d +(Client only) Delay traffic class. Pick one from {BK_SYS, BK, BE, RD, QAM, AV, RV, VI, VO, CTL}. +.El + +.Sh EXAMPLES +.Pp +Setup TCP server: +.Dl "frame_delay -m server -t tcp -p 10010 -n 10 -f 1000" +.Pp +Setup corresponding TCP client: +.Dl "frame_delay -m client -t tcp -i 127.0.0.1 -p 10010 -n 10 -f 1000 -d 2000 -k RD" + +.Sh AUTHORS +.An Padma Bhooma , +.An Kang Sun , +.An Vincent Lubet . \ No newline at end of file diff --git a/frame_delay/frame_delay.c b/frame_delay/frame_delay.c new file mode 100644 index 0000000..37a58b7 --- /dev/null +++ b/frame_delay/frame_delay.c @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2009-2015 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* + * Usage for frame_delay + * + * Server + * ./frame_delay -m server -t -p -n -f + * + * Client + * ./frame_delay -m client -t -i -p -n -f -d -k + */ + +/* + * TODO list : + * 1. UDP fragmentation and reassembly + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Server Static variable */ +static int so, srv_so; +static int srv_port = 0; +static struct sockaddr_in laddr, dst_addr; +/* Client Static variable */ +static struct sockaddr_in srv_addr; +static uint32_t tc = 0; +/* Usage */ +void ErrorUsage(void); +/* str2svc */ +uint32_t str2svc(const char *str); +/* Show Stastics */ +void ShowStastics(int64_t *DiffsBuf, int num_frames); +/* Returns difference between two timevals in microseconds */ +int64_t time_diff(struct timeval *b, struct timeval *a); +/* tcp server */ +void tcpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf); +/* udp server */ +void udpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf); +/* tcp server */ +void tcpClient(int num_frames, int frame_size, + const char *buf, struct timespec sleep_time); +/* udp server */ +void udpClient(int num_frames, int frame_size, + const char *buf, struct timespec sleep_time); + +/* Main function */ +int +main(int argc, char *argv[]) +{ + int num_frames = 0, frame_size = 0, delay_ms = 0, rc = 0; + char *buf = NULL, ch, *type = NULL, *mode = NULL, *ip_addr = NULL; + int64_t *DiffsBuf; + struct timespec sleep_time; + + while ((ch = getopt(argc, argv, "m:p:f:n:t:d:i:k:")) != -1) { + switch (ch) { + case 'm': { + mode = optarg; + break; + } + case 'p': { + srv_port = atoi(optarg); + break; + } + case 'f' : { + frame_size = atoi(optarg); + break; + } + case 'n' : { + num_frames = atoi(optarg); + break; + } + case 'i': { + ip_addr = optarg; + bzero(&srv_addr, sizeof(srv_addr)); + rc = inet_aton(optarg, &srv_addr.sin_addr); + if (rc == 0) { + perror("inet_ntoa failed"); + exit(1); + } + } + case 'd': { + delay_ms = atoi(optarg); + break; + } + case 't' : { + type = optarg; + break; + } + case 'k': { + tc = str2svc(optarg); + break; + } + default: { + printf("Invalid option: %c\n", ch); + ErrorUsage(); + } + } + } + /* General check for both server and client */ + if (srv_port <= 0 || frame_size <= 0 || num_frames <= 0 || !mode || !type) { + ErrorUsage(); + } + if ( strcmp(type, "tcp") != 0 && strcmp(type, "udp") != 0 ) { + ErrorUsage(); + } + /* Allocate memory for buf */ + buf = calloc(1, frame_size); + if (buf == NULL) { + printf("malloc failed\n"); + exit(1); + } + if ( strcmp(mode, "server") == 0 ) { + /* Server */ + printf(" : Start %s server on port %d with expected frame size of %d\n", + type, srv_port, frame_size); + DiffsBuf = (int64_t *)calloc(num_frames, sizeof(int64_t)); + if (DiffsBuf == NULL) { + printf("malloc failed\n"); + exit(1); + } + if( strcmp(type, "tcp") == 0) { + /* tcpServer */ + tcpServer(frame_size, num_frames, buf, DiffsBuf); + } else { + /* updServer */ + udpServer(frame_size, num_frames, buf, DiffsBuf); + } + } + else if ( strcmp(mode, "client") == 0 ){ + if ( !ip_addr || (tc > 0 && (tc < SO_TC_BK_SYS || tc > SO_TC_CTL)) ){ + ErrorUsage(); + } + /* Client */ + printf(" : Start sending %d %s frames to %s:%d with a frame size of %d\n", + num_frames, type, ip_addr, srv_port, frame_size); + /* Resolving sleep time bug : delay_ms should just be calculated once */ + bzero(&sleep_time, sizeof(sleep_time)); + while (delay_ms >= 1000) { + sleep_time.tv_sec++; + delay_ms -= 1000; + } + sleep_time.tv_nsec = delay_ms * 1000 * 1000; + if( strcmp(type, "tcp") == 0) { + /* Call TCP client */ + tcpClient(num_frames, frame_size, buf, sleep_time); + } else { + /* Call UDP client */ + udpClient(num_frames, frame_size, buf, sleep_time); + } + } else { + ErrorUsage(); + } +} + +/* Error usage */ +void +ErrorUsage(void) { + printf("Correct Usage"); + printf("Server : frame_delay -m server -t -p -n -f \n"); + printf("Client : frame_delay -m client -t -i -p -n -f -d -k \n"); + exit(1); +} + +/* str2svc */ +uint32_t +str2svc(const char *str) +{ + uint32_t svc; + char *endptr; + + if (str == NULL || *str == '\0') + svc = UINT32_MAX; + else if (strcasecmp(str, "BK_SYS") == 0) + return SO_TC_BK_SYS; + else if (strcasecmp(str, "BK") == 0) + return SO_TC_BK; + else if (strcasecmp(str, "BE") == 0) + return SO_TC_BE; + else if (strcasecmp(str, "RD") == 0) + return SO_TC_RD; + else if (strcasecmp(str, "OAM") == 0) + return SO_TC_OAM; + else if (strcasecmp(str, "AV") == 0) + return SO_TC_AV; + else if (strcasecmp(str, "RV") == 0) + return SO_TC_RV; + else if (strcasecmp(str, "VI") == 0) + return SO_TC_VI; + else if (strcasecmp(str, "VO") == 0) + return SO_TC_VO; + else if (strcasecmp(str, "CTL") == 0) + return SO_TC_CTL; + else { + svc = (uint32_t)strtoul(str, &endptr, 0); + if (*endptr != '\0') + svc = UINT32_MAX; + } + return (svc); +} + +/* Show Stastics */ +void +ShowStastics(int64_t *DiffsBuf, int num_frames) { + int i = 0; + int64_t sum = 0, mean = 0; + + /* Mean */ + while(i < num_frames) + sum += DiffsBuf[i++]; + mean = sum / num_frames; + printf(" : Mean: %.2f usecs\n", sum / (double)num_frames); + /* Popular Standard Deviation */ + i = 0; + sum = 0; + while(i < num_frames) { + sum += (DiffsBuf[i]-mean)*(DiffsBuf[i]-mean); + i++; + } + printf(" : Popular Standard Deviation: %.2f usecs\n", + sqrt(sum/(double)num_frames)); +} + +/* Returns difference between two timevals in microseconds */ +int64_t +time_diff(struct timeval *b, struct timeval *a) +{ + int64_t usecs; + usecs = (a->tv_sec - b->tv_sec) * 1000 * 1000; + usecs += (int64_t)(a->tv_usec - b->tv_usec); + return(usecs); +} + +/* Server */ + +/* tcp server */ +void +tcpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf) { + int rc = 0, i = 0, ignore_count = 0; + uint32_t dst_len = 0; + struct timeval before, after; + ssize_t bytes; + int64_t usecs; + /* New change from Padama */ + uint64_t prev_frame_ts = 0, prev_recv = 0, frame_ts = 0, cur_recv = 0; + uint64_t min_variation = 0, max_variation = 0, avg_variation = 0; + + printf(" : TCP Server\n"); + so = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (so == -1) { + perror("failed to create socket"); + exit(1); + } + bzero(&laddr, sizeof(laddr)); + laddr.sin_family = AF_INET; + laddr.sin_port = htons(srv_port); + rc = bind(so, (const struct sockaddr *)&laddr, sizeof(laddr)); + if (rc != 0) { + perror("failed to bind"); + exit(1); + } + rc = listen(so, 10); + if (rc != 0) { + perror("failed to listen"); + exit(1); + } + srv_so = accept(so, (struct sockaddr *)&dst_addr, &dst_len); + if (srv_so == -1) { + perror("failed to accept"); + exit(1); + } + while (1) { + if ( i == num_frames ) { + printf(" : Completed\n"); + break; + } + printf(" : Waiting for receiving\n"); + bzero(&before, sizeof(before)); + bzero(&after, sizeof(after)); + rc = gettimeofday(&before, NULL); + if (rc == -1) { + perror("gettimeofday failed"); + exit(1); + } + bytes = recv(srv_so, buf, frame_size, MSG_WAITALL); + if (bytes == -1) { + perror("recv failed"); + exit(1); + } + else if (bytes > 0 && bytes != frame_size) { + printf("Client exited\n"); + printf("Didn't recv the complete frame, bytes %ld\n", + bytes); + exit(1); + } + else if (bytes == 0) { + break; + } + rc = gettimeofday(&after, NULL); + if (rc == -1) { + perror("gettimeofday failed"); + exit(1); + } + cur_recv = after.tv_sec * 1000 * 1000 + after.tv_usec; + memcpy((void *)&frame_ts, buf, sizeof(frame_ts)); + if (prev_frame_ts > 0) { + int64_t d_variation = 0; + d_variation = (int64_t)((cur_recv - prev_recv) - + (frame_ts - prev_frame_ts)); + /* printf("Frame %u ts %llu d_variation %lld usecs\n", + i, frame_ts, d_variation);*/ + if (d_variation > 0) { + if (min_variation == 0) + min_variation = d_variation; + else + min_variation = ((min_variation <= d_variation) ? + min_variation : d_variation); + max_variation = ((max_variation >= d_variation) ? + max_variation : d_variation); + avg_variation += d_variation; + } else { + ignore_count++; + } + } + prev_recv = cur_recv; + prev_frame_ts = frame_ts; + ++i; + /* Compute the time differenc */ + usecs = time_diff(&before, &after); + DiffsBuf[i] = usecs; + printf(" : Frame %d received after %lld usecs\n", i, usecs); + } + if (i != ignore_count) + avg_variation = avg_variation / (i - ignore_count); + else + avg_variation = 0; + + printf(" : Received frames: %u\n", i); + printf(" : Ignored frames: %u\n", ignore_count); + printf(" : Minimum delay variation: %llu usecs\n", min_variation); + printf(" : Maximum delay variation: %llu usecs\n", max_variation); + printf(" : Average delay variation: %llu usecs\n", avg_variation); + ShowStastics(DiffsBuf, num_frames); +} + +/* udp server */ +void +udpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf) { + int rc = 0, i = 0, ignore_count = 0; + uint32_t dst_len = 0; + ssize_t bytes; + struct timeval before, after; + int64_t usecs; + /* New change from Padama */ + uint64_t prev_frame_ts = 0, prev_recv = 0, frame_ts = 0, cur_recv = 0; + uint64_t min_variation = 0, max_variation = 0, avg_variation = 0; + + printf(" : UDP Server\n"); + so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (so == -1) { + perror("failed to create socket"); + exit(1); + } + bzero(&laddr,sizeof(laddr)); + laddr.sin_family = AF_INET; + laddr.sin_addr.s_addr=htonl(INADDR_ANY); + laddr.sin_port=htons(srv_port); + rc = bind(so, (struct sockaddr *)&laddr,sizeof(laddr)); + if (rc != 0) { + perror("failed to bind"); + exit(1); + } + while (1) { + if ( i == num_frames ) { + printf(" : Completed\n"); + break; + } + printf(" : Waiting for receiving\n"); + bzero(&before, sizeof(before)); + bzero(&after, sizeof(after)); + rc = gettimeofday(&before, NULL); + if (rc == -1) { + perror("gettimeofday failed"); + exit(1); + } + bytes = recvfrom(so, buf, frame_size, 0, (struct sockaddr *)&dst_addr, &dst_len); + if (bytes == -1) { + perror("recv failed"); + exit(1); + } + else if (bytes > 0 && bytes != frame_size) { + printf("Client exited\n"); + printf("Didn't recv the complete frame, bytes %ld\n", + bytes); + exit(1); + } + else if (bytes == 0) { + break; + } + rc = gettimeofday(&after, NULL); + if (rc == -1) { + perror("gettimeofday failed"); + exit(1); + } + cur_recv = after.tv_sec * 1000 * 1000 + after.tv_usec; + memcpy((void *)&frame_ts, buf, sizeof(frame_ts)); + if (prev_frame_ts > 0) { + int64_t d_variation = 0; + + d_variation = (int64_t)((cur_recv - prev_recv) - + (frame_ts - prev_frame_ts)); + /* printf("Frame %u ts %llu d_variation %lld usecs\n", + i, frame_ts, d_variation);*/ + if (d_variation > 0) { + if (min_variation == 0) + min_variation = d_variation; + else + min_variation = ((min_variation <= d_variation) ? + min_variation : d_variation); + max_variation = ((max_variation >= d_variation) ? + max_variation : d_variation); + avg_variation += d_variation; + } else { + ignore_count++; + } + } + prev_recv = cur_recv; + prev_frame_ts = frame_ts; + ++i; + /* Compute the time differenc */ + usecs = time_diff(&before, &after); + DiffsBuf[i] = usecs; + printf(" : Frame %d received after %lld usecs\n", i, usecs); + } + if (i != ignore_count) + avg_variation = avg_variation / (i - ignore_count); + else + avg_variation = 0; + printf(" : Received frames: %u\n", i); + printf(" : Ignored frames: %u\n", ignore_count); + printf(" : Minimum delay variation: %llu usecs\n", min_variation); + printf(" : Maximum delay variation: %llu usecs\n", max_variation); + printf(" : Average delay variation: %llu usecs\n", avg_variation); + ShowStastics(DiffsBuf, num_frames); +} + +/* Client */ +void +tcpClient(int num_frames, int frame_size, + const char *buf, struct timespec sleep_time){ + int rc = 0, i = 0; + ssize_t bytes; + + printf(" : TCP Client\n"); + so = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (so <= 0) { + perror("creating socket failed"); + exit(1); + } + srv_addr.sin_port = htons(srv_port); + srv_addr.sin_len = sizeof(srv_addr); + srv_addr.sin_family = AF_INET; + rc = connect(so, (const struct sockaddr *)&srv_addr, + sizeof(srv_addr)); + if (rc != 0) { + perror("connect failed"); + exit(1); + } + if (tc > 0) { + rc = setsockopt(so, SOL_SOCKET, SO_TRAFFIC_CLASS, &tc, + sizeof(tc)); + if (rc == -1) { + perror("failed to set traffic class"); + exit(1); + } + } + for (i = 0; i < num_frames; ++i) { + struct timeval fts; + uint64_t frame_ts; + /* Add a timestamp to the frame */ + rc = gettimeofday(&fts, NULL); + if (rc == -1) { + perror("faile to get time of day"); + exit(1); + } + frame_ts = fts.tv_sec * 1000 * 1000 + fts.tv_usec; + memcpy((void *)buf, (const void *)&frame_ts, sizeof(frame_ts)); + bytes = send(so, buf, frame_size, 0); + if (bytes == -1) { + perror("send failed \n"); + exit(1); + } + if (bytes != frame_size) { + printf("failed to send all bytes, sent %ld\n", bytes); + exit (1); + } + rc = nanosleep(&sleep_time, NULL); + if (rc == -1) { + perror("sleep failed"); + exit(1); + } + printf(" : Sent %u frames as a whole\n", (i + 1)); + } +} + +void +udpClient(int num_frames, int frame_size, + const char *buf, struct timespec sleep_time){ + int rc = 0, i = 0; + ssize_t bytes; + + printf(" : UDP Client\n"); + so = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (so <= 0) { + perror("creating socket failed"); + exit(1); + } + srv_addr.sin_port = htons(srv_port); + srv_addr.sin_len = sizeof(srv_addr); + srv_addr.sin_family = AF_INET; + if (tc > 0) { + rc = setsockopt(so, SOL_SOCKET, SO_TRAFFIC_CLASS, &tc, + sizeof(tc)); + if (rc == -1) { + perror("failed to set traffic class"); + exit(1); + } + } + for (i = 0; i < num_frames; ++i) { + struct timeval fts; + uint64_t frame_ts; + /* Add a timestamp to the frame */ + rc = gettimeofday(&fts, NULL); + if (rc == -1) { + perror("faile to get time of day"); + exit(1); + } + frame_ts = fts.tv_sec * 1000 * 1000 + fts.tv_usec; + memcpy((void *)buf, (const void *)&frame_ts, sizeof(frame_ts)); + bytes = sendto(so, buf, frame_size, 0, (struct sockaddr *)&srv_addr, sizeof(srv_addr)); + if (bytes == -1) { + perror("send failed \n"); + exit(1); + } + if (bytes != frame_size) { + printf("failed to send all bytes, sent %ld\n", bytes); + exit (1); + } + rc = nanosleep(&sleep_time, NULL); + if (rc == -1) { + perror("sleep failed"); + exit(1); + } + printf(" : Sent %u frames as a whole\n", (i + 1)); + } +} + + diff --git a/ifconfig.tproj/af_inet6.c b/ifconfig.tproj/af_inet6.c index 4a9c8fa..d2a5b1b 100644 --- a/ifconfig.tproj/af_inet6.c +++ b/ifconfig.tproj/af_inet6.c @@ -83,7 +83,7 @@ #define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \ "\004IFDISABLED\005DONT_SET_IFROUTE\006PROXY_PREFIXES" \ - "\007IGNORE_NA\010INSECURE" + "\007IGNORE_NA\010INSECURE\011REPLICATED\012DAD" static struct in6_ifreq in6_ridreq; static struct in6_aliasreq in6_addreq = @@ -607,8 +607,8 @@ static struct cmd inet6_cmds[] = { DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags), DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags), DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags), - DEF_CMD("ignore_na", ND6_IFF_IGNORE_NA, setnd6flags), - DEF_CMD("-ignore_na", -ND6_IFF_IGNORE_NA, setnd6flags), + DEF_CMD("replicated", ND6_IFF_REPLICATED, setnd6flags), + DEF_CMD("-replicated", -ND6_IFF_REPLICATED, setnd6flags), DEF_CMD("proxy_prefixes", ND6_IFF_PROXY_PREFIXES, setnd6flags), DEF_CMD("-proxy_prefixes", -ND6_IFF_PROXY_PREFIXES, setnd6flags), DEF_CMD("insecure", ND6_IFF_INSECURE, setnd6flags), @@ -618,6 +618,8 @@ static struct cmd inet6_cmds[] = { DEF_CMD("eui64", 0, setip6eui64), DEF_CMD("secured", IN6_IFF_SECURED, setip6flags), DEF_CMD("-secured", -IN6_IFF_SECURED, setip6flags), + DEF_CMD("dad", ND6_IFF_DAD, setnd6flags), + DEF_CMD("-dad", -ND6_IFF_DAD, setnd6flags), }; static struct afswtch af_inet6 = { diff --git a/ifconfig.tproj/ifconfig.8 b/ifconfig.tproj/ifconfig.8 index 6a7ea05..9b06f04 100644 --- a/ifconfig.tproj/ifconfig.8 +++ b/ifconfig.tproj/ifconfig.8 @@ -558,6 +558,16 @@ Do not disable all IPv6 communication on the interface. Disable the processing of Secure Neighbor Discovery (SEND). .It Cm -insecure Do not disabled the processing of Secure Neighbor Discovery (SEND). +.It Cm dad +Perform duplicate address detection (DAD). +.It Cm -dad +Do not perform duplicate address detection (DAD). +.It Cm replicated +Modify duplicate address detection (DAD) protocol to expect that interface +configuration is replicated at a network sleep proxy. Ignores certain NA +messages and disables optimistic DAD. +.It Cm -replicated +Do not use modified duplicated address detection (DAD) protocol. .El .Pp The following parameters are specific to link aggregate interfaces: diff --git a/ifconfig.tproj/ifconfig.c b/ifconfig.tproj/ifconfig.c index 1a708da..d20a2f7 100644 --- a/ifconfig.tproj/ifconfig.c +++ b/ifconfig.tproj/ifconfig.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Apple Inc. All rights reserved. + * Copyright (c) 2009-2015 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -98,6 +98,7 @@ __unused static const char copyright[] = #include #include #include +#include #include "ifconfig.h" @@ -762,7 +763,6 @@ setifflags(const char *vname, int value, int s, const struct afswtch *afp) Perror(vname); } -#ifdef SIOCGIFCAP void setifcap(const char *vname, int value, int s, const struct afswtch *afp) { @@ -783,7 +783,6 @@ setifcap(const char *vname, int value, int s, const struct afswtch *afp) if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0) Perror(vname); } -#endif static void setifmetric(const char *val, int dummy __unused, int s, @@ -940,6 +939,33 @@ setthrottle(const char *val, int dummy __unused, int s, } } +static void +setdisableoutput(const char *val, int dummy __unused, int s, + const struct afswtch *afp) +{ + struct ifreq ifr; + char *cp; + errno = 0; + bzero(&ifr, sizeof (ifr)); + strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + + ifr.ifr_ifru.ifru_disable_output = strtold(val, &cp); + if (val == cp || errno != 0) { + warn("Invalid value '%s'", val); + return; + } + + if (ioctl(s, SIOCSIFDISABLEOUTPUT, &ifr) < 0 && errno != ENXIO) { + warn("ioctl set disable output"); + } else if (errno == ENXIO) { + printf("output thread can not be disabled on %s\n", name); + } else { + printf("output %s on %s\n", + ((ifr.ifr_ifru.ifru_disable_output == 0) ? "enabled" : "disabled"), + name); + } +} + static void setlog(const char *val, int dummy __unused, int s, const struct afswtch *afp) @@ -981,6 +1007,19 @@ setexpensive(const char *vname, int value, int s, const struct afswtch *afp) Perror(vname); } +void +settimestamp(const char *vname, int value, int s, const struct afswtch *afp) +{ + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + if (value == 0) { + if (ioctl(s, SIOCSIFTIMESTAMPDISABLE, (caddr_t)&ifr) < 0) + Perror(vname); + } else { + if (ioctl(s, SIOCSIFTIMESTAMPENABLE, (caddr_t)&ifr) < 0) + Perror(vname); + } +} void setecnmode(const char *val, int dummy __unused, int s, @@ -1008,6 +1047,137 @@ setecnmode(const char *val, int dummy __unused, int s, Perror("ioctl(SIOCSECNMODE)"); } +#if defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) + +void +setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp) +{ + u_long ioc; + +#if (DEBUG | DEVELOPMENT) + printf("%s(%s, %s)\n", __func__, cmd, arg); +#endif /* (DEBUG | DEVELOPMENT) */ + + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + if (strcmp(cmd, "mode") == 0) { + ioc = SIOCSQOSMARKINGMODE; + + if (strcmp(arg, "fastlane") == 0) + ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_FASTLANE; + else if (strcasecmp(arg, "none") == 0 || strcasecmp(arg, "off") == 0) + ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_MODE_NONE; + else + err(EX_USAGE, "bad value for qosmarking mode: %s", arg); + } else if (strcmp(cmd, "enabled") == 0) { + ioc = SIOCSQOSMARKINGENABLED; + if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0|| + strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0) + ifr.ifr_qosmarking_enabled = 1; + else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0|| + strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0) + ifr.ifr_qosmarking_enabled = 0; + else + err(EX_USAGE, "bad value for qosmarking enabled: %s", arg); + } else { + err(EX_USAGE, "qosmarking takes mode or enabled"); + } + + if (ioctl(s, ioc, (caddr_t)&ifr) < 0) + err(EX_OSERR, "ioctl(%s, %s)", cmd, arg); +} + +void +setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp) +{ + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + warnx("### fastlane is obsolete, use qosmarking ###"); + + if (strcmp(cmd, "capable") == 0) { + if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0|| + strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0) + setqosmarking("mode", "fastlane", s, afp); + else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0|| + strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0) + setqosmarking("mode", "off", s, afp); + else + err(EX_USAGE, "bad value for fastlane %s", cmd); + } else if (strcmp(cmd, "enable") == 0) { + if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0|| + strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0) + setqosmarking("enabled", "1", s, afp); + else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0|| + strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0) + setqosmarking("enabled", "0", s, afp); + else + err(EX_USAGE, "bad value for fastlane %s", cmd); + } else { + err(EX_USAGE, "fastlane takes capable or enable"); + } +} + +#else /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */ + +void +setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp) +{ + int value; + u_long ioc; + + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + if (strcmp(cmd, "capable") == 0) + ioc = SIOCSFASTLANECAPABLE; + else if (strcmp(cmd, "enable") == 0) + ioc = SIOCSFASTLEENABLED; + else + err(EX_USAGE, "fastlane takes capable or enabled"); + + if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0|| + strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0) + value = 1; + else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0|| + strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0) + value = 0; + else + err(EX_USAGE, "bad value for fastlane %s", cmd); + + if (ioc == SIOCSFASTLANECAPABLE) + ifr.ifr_fastlane_capable = value; + else + ifr.ifr_fastlane_enabled = value; + + if (ioctl(s, ioc, (caddr_t)&ifr) < 0) + err(EX_OSERR, "ioctl(%s, %s)", cmd, arg); +} + + +void +setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp) +{ + if (strcmp(cmd, "mode") == 0) { + if (strcmp(arg, "fastlane") == 0) + setfastlane("capable", "on", s, afp); + else if (strcmp(arg, "none") == 0) + setfastlane("capable", "off", s, afp); + else + err(EX_USAGE, "bad value for qosmarking mode: %s", arg); + } else if (strcmp(cmd, "enabled") == 0) { + if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0|| + strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0) + setfastlane("enable", "on", s, afp); + else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0|| + strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0) + setfastlane("enable", "off", s, afp); + else + err(EX_USAGE, "bad value for qosmarking enabled: %s", arg); + } else { + err(EX_USAGE, "qosmarking takes mode or enabled"); + } +} + +#endif /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */ #define IFFBITS \ "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \ @@ -1015,14 +1185,15 @@ setecnmode(const char *val, int dummy __unused, int s, "\20MULTICAST" #define IFEFBITS \ -"\020\1AUTOCONFIGURING\6IPV6_DISABLED\7ACCEPT_RTADV\10TXSTART\11RXPOLL" \ +"\020\1AUTOCONFIGURING\5FASTLN_CAP\6IPV6_DISABLED\7ACCEPT_RTADV\10TXSTART\11RXPOLL" \ "\12VLAN\13BOND\14ARPLL\15NOWINDOWSCALE\16NOAUTOIPV6LL\17EXPENSIVE\20ROUTER4" \ "\21ROUTER6\22LOCALNET_PRIVATE\23ND6ALT\24RESTRICTED_RECV\25AWDL\26NOACKPRI" \ -"\27AWDL_RESTRICTED\30CL2K\31ECN_ENABLE\32ECN_DISABLE\35SENDLIST\36DIRECTLINK\40UPDOWNCHANGE" +"\27AWDL_RESTRICTED\30CL2K\31ECN_ENABLE\32ECN_DISABLE\34CA\35SENDLIST\36DIRECTLINK" \ +"\37FASTLN_ON\40UPDOWNCHANGE" #define IFCAPBITS \ "\020\1RXCSUM\2TXCSUM\3VLAN_MTU\4VLAN_HWTAGGING\5JUMBO_MTU" \ -"\6TSO4\7TSO6\10LRO\11AV\12TXSTATUS" +"\6TSO4\7TSO6\10LRO\11AV\12TXSTATUS\14HW_TIMESTAMP\15SW_TIMESTAMP" #define IFRLOGF_BITS \ "\020\1DLIL\21FAMILY\31DRIVER\35FIRMWARE" @@ -1044,7 +1215,8 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl, struct ifmibdata_supplemental ifmsupp; size_t miblen = sizeof(struct ifmibdata_supplemental); u_int64_t eflags = 0; - + int curcap = 0; + if (afp == NULL) { allfamilies = 1; afp = af_getbyname("inet"); @@ -1067,11 +1239,11 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl, printf(" mtu %d", ifr.ifr_mtu); if (showrtref && ioctl(s, SIOCGIFGETRTREFCNT, &ifr) != -1) printf(" rtref %d", ifr.ifr_route_refcnt); - if (verbose) { - unsigned int ifindex = if_nametoindex(ifa->ifa_name); - if (ifindex != 0) - printf(" index %u", ifindex); - } + if (verbose) { + unsigned int ifindex = if_nametoindex(ifa->ifa_name); + if (ifindex != 0) + printf(" index %u", ifindex); + } putchar('\n'); if (verbose && ioctl(s, SIOCGIFEFLAGS, (caddr_t)&ifr) != -1 && @@ -1080,9 +1252,9 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl, putchar('\n'); } -#ifdef SIOCGIFCAP if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) { if (ifr.ifr_curcap != 0) { + curcap = ifr.ifr_curcap; printb("\toptions", ifr.ifr_curcap, IFCAPBITS); putchar('\n'); } @@ -1091,7 +1263,6 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl, putchar('\n'); } } -#endif tunnel_status(s); @@ -1402,7 +1573,7 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl, printf("\teffective interface: %s\n", delegatedif); } - if(ioctl(s, SIOCGSTARTDELAY, &ifr) != -1) { + if (ioctl(s, SIOCGSTARTDELAY, &ifr) != -1) { if (ifr.ifr_start_delay_qlen > 0 && ifr.ifr_start_delay_timeout > 0) { printf("\ttxstart qlen: %u packets " @@ -1411,7 +1582,32 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl, ifr.ifr_start_delay_timeout/1000); } } - +#if defined(IFCAP_HW_TIMESTAMP) && defined(IFCAP_SW_TIMESTAMP) + if ((curcap & (IFCAP_HW_TIMESTAMP | IFCAP_SW_TIMESTAMP)) && + ioctl(s, SIOCGIFTIMESTAMPENABLED, &ifr) != -1) { + printf("\ttimestamp: %s\n", + (ifr.ifr_intval != 0) ? "enabled" : "disabled"); + } +#endif +#if defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE) + if (ioctl(s, SIOCGQOSMARKINGENABLED, &ifr) != -1) { + printf("\tqosmarking enabled: %s mode: ", + ifr.ifr_qosmarking_enabled ? "yes" : "no"); + if (ioctl(s, SIOCGQOSMARKINGMODE, &ifr) != -1) { + switch (ifr.ifr_qosmarking_mode) { + case IFRTYPE_QOSMARKING_FASTLANE: + printf("fastlane\n"); + break; + case IFRTYPE_QOSMARKING_MODE_NONE: + printf("none\n"); + break; + default: + printf("unknown (%u)\n", ifr.ifr_qosmarking_mode); + break; + } + } + } +#endif /* defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE) */ done: close(s); return; @@ -1715,7 +1911,12 @@ static struct cmd basic_cmds[] = { DEF_CMD("-cl2k", 0, setcl2k), DEF_CMD("expensive", 1, setexpensive), DEF_CMD("-expensive", 0, setexpensive), + DEF_CMD("timestamp", 1, settimestamp), + DEF_CMD("-timestamp", 0, settimestamp), DEF_CMD_ARG("ecn", setecnmode), + DEF_CMD_ARG2("fastlane", setfastlane), + DEF_CMD_ARG2("qosmarking", setqosmarking), + DEF_CMD_ARG("disable_output", setdisableoutput), }; static __constructor void diff --git a/ip6fw.tproj/ip6fw.8 b/ip6fw.tproj/ip6fw.8 deleted file mode 100644 index 9915ea7..0000000 --- a/ip6fw.tproj/ip6fw.8 +++ /dev/null @@ -1,11 +0,0 @@ -.Dd September 27, 2012 -.Dt IP6FW 8 -.Os Darwin -.Sh NAME -.Nm ip6fw -.Sh DESCRIPTION -This utility is -.Cm DEPRECATED. -Please use -.Xr pfctl 8 -instead. diff --git a/ip6fw.tproj/ip6fw.c b/ip6fw.tproj/ip6fw.c deleted file mode 100644 index baaa620..0000000 --- a/ip6fw.tproj/ip6fw.c +++ /dev/null @@ -1,1446 +0,0 @@ -/* - * Copyright (c) 2009 Apple Inc. All rights reserved. - * - * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the License - * may not be used to create, or enable the creation or redistribution of, - * unlawful or unlicensed copies of an Apple operating system, or to - * circumvent, violate, or enable the circumvention or violation of, any - * terms of an Apple operating system software license agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ - */ - -/* - * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp - * Copyright (c) 1994 Ugen J.S.Antsilevich - * - * Idea and grammar partially left from: - * Copyright (c) 1993 Daniel Boulet - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. - * - * NEW command line interface for IP firewall facility - * - * $Id: ip6fw.c,v 1.3 2006/02/07 06:22:17 lindak Exp $ - * $FreeBSD: src/sbin/ip6fw/ip6fw.c,v 1.1.2.6 2001/08/01 06:52:18 obrien Exp $ - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -int lineno = -1; - -int s; /* main RAW socket */ -int do_resolv=0; /* Would try to resolv all */ -int do_acct=0; /* Show packet/byte count */ -int do_time=0; /* Show time stamps */ -int do_quiet=0; /* Be quiet in add and flush */ -int do_force=0; /* Don't ask for confirmation */ - -struct icmpcode { - int code; - char *str; -}; - -static struct icmpcode icmp6codes[] = { - { ICMP6_DST_UNREACH_NOROUTE, "noroute" }, - { ICMP6_DST_UNREACH_ADMIN, "admin" }, - { ICMP6_DST_UNREACH_NOTNEIGHBOR, "notneighbor" }, - { ICMP6_DST_UNREACH_ADDR, "addr" }, - { ICMP6_DST_UNREACH_NOPORT, "noport" }, - { 0, NULL } -}; - -static char ntop_buf[INET6_ADDRSTRLEN]; - -static void show_usage(const char *fmt, ...); - -static int -mask_bits(u_char *m_ad, int m_len) -{ - int h_num = 0,i; - - for (i = 0; i < m_len; i++, m_ad++) { - if (*m_ad != 0xff) - break; - h_num += 8; - } - if (i < m_len) { - switch (*m_ad) { -#define MASKLEN(m, l) case m: h_num += l; break - MASKLEN(0xfe, 7); - MASKLEN(0xfc, 6); - MASKLEN(0xf8, 5); - MASKLEN(0xf0, 4); - MASKLEN(0xe0, 3); - MASKLEN(0xc0, 2); - MASKLEN(0x80, 1); -#undef MASKLEN - } - } - return h_num; -} - -static int pl2m[9] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; - -struct in6_addr *plen2mask(int n) -{ - static struct in6_addr ia; - u_char *p; - int i; - - memset(&ia, 0, sizeof(struct in6_addr)); - p = (u_char *)&ia; - for (i = 0; i < 16; i++, p++, n -= 8) { - if (n >= 8) { - *p = 0xff; - continue; - } - *p = pl2m[n]; - break; - } - return &ia; -} - -void -print_port(prot, port, comma) - u_char prot; - u_short port; - const char *comma; -{ - struct servent *se; - struct protoent *pe; - const char *protocol; - int printed = 0; - - if (do_resolv) { - pe = getprotobynumber(prot); - if (pe) - protocol = pe->p_name; - else - protocol = NULL; - - se = getservbyport(htons(port), protocol); - if (se) { - printf("%s%s", comma, se->s_name); - printed = 1; - } - } - if (!printed) - printf("%s%d",comma,port); -} - -static void -print_iface(char *key, union ip6_fw_if *un, int byname) -{ - char ifnb[IP6FW_IFNLEN+1]; - - if (byname) { - strncpy(ifnb, un->fu_via_if.name, IP6FW_IFNLEN); - ifnb[IP6FW_IFNLEN]='\0'; - if (un->fu_via_if.unit == -1) - printf(" %s %s*", key, ifnb); - else - printf(" %s %s%d", key, ifnb, un->fu_via_if.unit); - } else if (!IN6_IS_ADDR_UNSPECIFIED(&un->fu_via_ip6)) { - printf(" %s %s", key, inet_ntop(AF_INET6,&un->fu_via_ip6,ntop_buf,sizeof(ntop_buf))); - } else - printf(" %s any", key); -} - -static void -print_reject_code(int code) -{ - struct icmpcode *ic; - - for (ic = icmp6codes; ic->str; ic++) - if (ic->code == code) { - printf("%s", ic->str); - return; - } - printf("%u", code); -} - -static void -show_ip6fw(struct ip6_fw *chain) -{ - char *comma; - struct hostent *he; - struct protoent *pe; - int i, mb; - int nsp = IPV6_FW_GETNSRCP(chain); - int ndp = IPV6_FW_GETNDSTP(chain); - - if (do_resolv) - setservent(1/*stayopen*/); - - printf("%05u ", chain->fw_number); - - if (do_acct) - printf("%10u %10u ",chain->fw_pcnt,chain->fw_bcnt); - - if (do_time) - { - if (chain->timestamp) - { - char timestr[30]; - - strlcpy(timestr, ctime((time_t *)&chain->timestamp), sizeof(timestr)); - *strchr(timestr, '\n') = '\0'; - printf("%s ", timestr); - } - else - printf(" "); - } - - switch (chain->fw_flg & IPV6_FW_F_COMMAND) - { - case IPV6_FW_F_ACCEPT: - printf("allow"); - break; - case IPV6_FW_F_DENY: - printf("deny"); - break; - case IPV6_FW_F_COUNT: - printf("count"); - break; - case IPV6_FW_F_DIVERT: - printf("divert %u", chain->fw_divert_port); - break; - case IPV6_FW_F_TEE: - printf("tee %u", chain->fw_divert_port); - break; - case IPV6_FW_F_SKIPTO: - printf("skipto %u", chain->fw_skipto_rule); - break; - case IPV6_FW_F_REJECT: - if (chain->fw_reject_code == IPV6_FW_REJECT_RST) - printf("reset"); - else { - printf("unreach "); - print_reject_code(chain->fw_reject_code); - } - break; - default: - errx(EX_OSERR, "impossible"); - } - - if (chain->fw_flg & IPV6_FW_F_PRN) - printf(" log"); - - pe = getprotobynumber(chain->fw_prot); - if (pe) - printf(" %s", pe->p_name); - else - printf(" %u", chain->fw_prot); - - printf(" from %s", chain->fw_flg & IPV6_FW_F_INVSRC ? "not " : ""); - - mb=mask_bits((u_char *)&chain->fw_smsk,sizeof(chain->fw_smsk)); - if (mb==128 && do_resolv) { - he=gethostbyaddr((char *)&(chain->fw_src),sizeof(chain->fw_src),AF_INET6); - if (he==NULL) { - printf("%s", inet_ntop(AF_INET6,&chain->fw_src,ntop_buf,sizeof(ntop_buf))); - } else - printf("%s",he->h_name); - } else { - if (mb!=128) { - if (mb == 0) { - printf("any"); - } else { - printf("%s", inet_ntop(AF_INET6,&chain->fw_src,ntop_buf,sizeof(ntop_buf))); - printf("/%d",mb); - } - } else - printf("%s", inet_ntop(AF_INET6,&chain->fw_src,ntop_buf,sizeof(ntop_buf))); - } - - if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) { - comma = " "; - for (i = 0; i < nsp; i++) { - print_port(chain->fw_prot, chain->fw_pts[i], comma); - if (i==0 && (chain->fw_flg & IPV6_FW_F_SRNG)) - comma = "-"; - else - comma = ","; - } - } - - printf(" to %s", chain->fw_flg & IPV6_FW_F_INVDST ? "not " : ""); - - mb=mask_bits((u_char *)&chain->fw_dmsk,sizeof(chain->fw_dmsk)); - if (mb==128 && do_resolv) { - he=gethostbyaddr((char *)&(chain->fw_dst),sizeof(chain->fw_dst),AF_INET); - if (he==NULL) { - printf("%s", inet_ntop(AF_INET6,&chain->fw_dst,ntop_buf,sizeof(ntop_buf))); - } else - printf("%s",he->h_name); - } else { - if (mb!=128) { - if (mb == 0) { - printf("any"); - } else { - printf("%s", inet_ntop(AF_INET6,&chain->fw_dst,ntop_buf,sizeof(ntop_buf))); - printf("/%d",mb); - } - } else - printf("%s", inet_ntop(AF_INET6,&chain->fw_dst,ntop_buf,sizeof(ntop_buf))); - } - - if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) { - comma = " "; - for (i = 0; i < ndp; i++) { - print_port(chain->fw_prot, chain->fw_pts[nsp+i], comma); - if (i==0 && (chain->fw_flg & IPV6_FW_F_DRNG)) - comma = "-"; - else - comma = ","; - } - } - - /* Direction */ - if ((chain->fw_flg & IPV6_FW_F_IN) && !(chain->fw_flg & IPV6_FW_F_OUT)) - printf(" in"); - if (!(chain->fw_flg & IPV6_FW_F_IN) && (chain->fw_flg & IPV6_FW_F_OUT)) - printf(" out"); - - /* Handle hack for "via" backwards compatibility */ - if ((chain->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) { - print_iface("via", - &chain->fw_in_if, chain->fw_flg & IPV6_FW_F_IIFNAME); - } else { - /* Receive interface specified */ - if (chain->fw_flg & IPV6_FW_F_IIFACE) - print_iface("recv", &chain->fw_in_if, - chain->fw_flg & IPV6_FW_F_IIFNAME); - /* Transmit interface specified */ - if (chain->fw_flg & IPV6_FW_F_OIFACE) - print_iface("xmit", &chain->fw_out_if, - chain->fw_flg & IPV6_FW_F_OIFNAME); - } - - if (chain->fw_flg & IPV6_FW_F_FRAG) - printf(" frag"); - - if (chain->fw_ip6opt || chain->fw_ip6nopt) { - int _opt_printed = 0; -#define PRINTOPT(x) {if (_opt_printed) printf(",");\ - printf(x); _opt_printed = 1;} - - printf(" ip6opt "); - if (chain->fw_ip6opt & IPV6_FW_IP6OPT_HOPOPT) PRINTOPT("hopopt"); - if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_HOPOPT) PRINTOPT("!hopopt"); - if (chain->fw_ip6opt & IPV6_FW_IP6OPT_ROUTE) PRINTOPT("route"); - if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_ROUTE) PRINTOPT("!route"); - if (chain->fw_ip6opt & IPV6_FW_IP6OPT_FRAG) PRINTOPT("frag"); - if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_FRAG) PRINTOPT("!frag"); - if (chain->fw_ip6opt & IPV6_FW_IP6OPT_ESP) PRINTOPT("esp"); - if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_ESP) PRINTOPT("!esp"); - if (chain->fw_ip6opt & IPV6_FW_IP6OPT_AH) PRINTOPT("ah"); - if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_AH) PRINTOPT("!ah"); - if (chain->fw_ip6opt & IPV6_FW_IP6OPT_NONXT) PRINTOPT("nonxt"); - if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_NONXT) PRINTOPT("!nonxt"); - if (chain->fw_ip6opt & IPV6_FW_IP6OPT_OPTS) PRINTOPT("opts"); - if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_OPTS) PRINTOPT("!opts"); - } - - if (chain->fw_ipflg & IPV6_FW_IF_TCPEST) - printf(" established"); - else if (chain->fw_tcpf == IPV6_FW_TCPF_SYN && - chain->fw_tcpnf == IPV6_FW_TCPF_ACK) - printf(" setup"); - else if (chain->fw_tcpf || chain->fw_tcpnf) { - int _flg_printed = 0; -#define PRINTFLG(x) {if (_flg_printed) printf(",");\ - printf(x); _flg_printed = 1;} - - printf(" tcpflg "); - if (chain->fw_tcpf & IPV6_FW_TCPF_FIN) PRINTFLG("fin"); - if (chain->fw_tcpnf & IPV6_FW_TCPF_FIN) PRINTFLG("!fin"); - if (chain->fw_tcpf & IPV6_FW_TCPF_SYN) PRINTFLG("syn"); - if (chain->fw_tcpnf & IPV6_FW_TCPF_SYN) PRINTFLG("!syn"); - if (chain->fw_tcpf & IPV6_FW_TCPF_RST) PRINTFLG("rst"); - if (chain->fw_tcpnf & IPV6_FW_TCPF_RST) PRINTFLG("!rst"); - if (chain->fw_tcpf & IPV6_FW_TCPF_PSH) PRINTFLG("psh"); - if (chain->fw_tcpnf & IPV6_FW_TCPF_PSH) PRINTFLG("!psh"); - if (chain->fw_tcpf & IPV6_FW_TCPF_ACK) PRINTFLG("ack"); - if (chain->fw_tcpnf & IPV6_FW_TCPF_ACK) PRINTFLG("!ack"); - if (chain->fw_tcpf & IPV6_FW_TCPF_URG) PRINTFLG("urg"); - if (chain->fw_tcpnf & IPV6_FW_TCPF_URG) PRINTFLG("!urg"); - } - if (chain->fw_flg & IPV6_FW_F_ICMPBIT) { - int type_index; - int first = 1; - - printf(" icmptype"); - - for (type_index = 0; type_index < IPV6_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8; ++type_index) - if (chain->fw_icmp6types[type_index / (sizeof(unsigned) * 8)] & - (1U << (type_index % (sizeof(unsigned) * 8)))) { - printf("%c%d", first == 1 ? ' ' : ',', type_index); - first = 0; - } - } - printf("\n"); - if (do_resolv) - endservent(); -} - -void -list(ac, av) - int ac; - char **av; -{ - struct ip6_fw *r, *rules; - int l,i; - unsigned long rulenum; - int nalloc, maxbytes; - socklen_t bytes; - - /* extract rules from kernel, resizing array as necessary */ - rules = NULL; - nalloc = sizeof *rules; - bytes = nalloc; - maxbytes = 65536 * sizeof *rules; - while (bytes >= nalloc) { - nalloc = nalloc * 2 + 200; - bytes = nalloc; - if ((rules = realloc(rules, bytes)) == NULL) - err(EX_OSERR, "realloc"); - memset(rules, 0, sizeof *rules); - rules->version = IPV6_FW_CURRENT_API_VERSION; - i = getsockopt(s, IPPROTO_IPV6, IPV6_FW_GET, rules, &bytes); - if ((i < 0 && errno != EINVAL) || nalloc > maxbytes) - err(EX_OSERR, "getsockopt(IPV6_FW_GET)"); - } - if (!ac) { - /* display all rules */ - for (r = rules, l = bytes; l >= sizeof rules[0]; - r++, l-=sizeof rules[0]) - show_ip6fw(r); - } - else { - /* display specific rules requested on command line */ - int exitval = 0; - - while (ac--) { - char *endptr; - int seen; - - /* convert command line rule # */ - rulenum = strtoul(*av++, &endptr, 10); - if (*endptr) { - exitval = 1; - warn("invalid rule number: %s", av[-1]); - continue; - } - seen = 0; - for (r = rules, l = bytes; - l >= sizeof rules[0] && r->fw_number <= rulenum; - r++, l-=sizeof rules[0]) - if (rulenum == r->fw_number) { - show_ip6fw(r); - seen = 1; - } - if (!seen) { - exitval = 1; - warnx("rule %lu does not exist", rulenum); - } - } - if (exitval != 0) - exit(exitval); - } -} - -static void -show_usage(const char *fmt, ...) -{ - if (fmt) { - char buf[100]; - va_list args; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - warnx("error: %s", buf); - } - fprintf(stderr, "usage: ip6fw [options]\n" -" flush\n" -" add [number] rule\n" -" delete number ...\n" -" list [number ...]\n" -" show [number ...]\n" -" zero [number ...]\n" -" rule: action proto src dst extras...\n" -" action:\n" -" {allow|permit|accept|pass|deny|drop|reject|unreach code|\n" -" reset|count|skipto num} [log]\n" -" proto: {ipv6|tcp|udp|ipv6-icmp|}\n" -" src: from [not] {any|ipv6[/prefixlen]} [{port|port-port},[port],...]\n" -" dst: to [not] {any|ipv6[/prefixlen]} [{port|port-port},[port],...]\n" -" extras:\n" -" fragment (may not be used with ports or tcpflags)\n" -" in\n" -" out\n" -" {xmit|recv|via} {iface|ipv6|any}\n" -" {established|setup}\n" -" tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n" -" ipv6options [!]{hopopt|route|frag|esp|ah|nonxt|opts},...\n" -" icmptypes {type[,type]}...\n"); - - exit(1); -} - -static int -lookup_host (host, addr, family) - char *host; - u_char *addr; -{ - struct hostent *he = gethostbyname2(host, family); - - if (!he) - return(-1); - - memcpy(addr, he->h_addr_list[0], he->h_length); - - return(0); -} - -void -fill_ip6(ipno, mask, acp, avp) - struct in6_addr *ipno, *mask; - int *acp; - char ***avp; -{ - int ac = *acp; - char **av = *avp; - char *p = 0, md = 0; - int i; - - if (ac && !strncmp(*av,"any",strlen(*av))) { - *ipno = *mask = in6addr_any; av++; ac--; - } else { - p = strchr(*av, '/'); - if (p) { - md = *p; - *p++ = '\0'; - } - - if (lookup_host(*av, (u_char *)ipno, AF_INET6) != 0) - show_usage("hostname ``%s'' unknown", *av); - switch (md) { - case '/': - if (atoi(p) == 0) { - *mask = in6addr_any; - } else if (atoi(p) > 128) { - show_usage("bad width ``%s''", p); - } else { - *mask = *(plen2mask(atoi(p))); - } - break; - default: - *mask = *(plen2mask(128)); - break; - } - for (i = 0; i < sizeof(*ipno); i++) - ipno->s6_addr[i] &= mask->s6_addr[i]; - av++; - ac--; - } - *acp = ac; - *avp = av; -} - -static void -fill_reject_code6(u_short *codep, char *str) -{ - struct icmpcode *ic; - u_long val; - char *s; - - val = strtoul(str, &s, 0); - if (s != str && *s == '\0' && val < 0x100) { - *codep = val; - return; - } - for (ic = icmp6codes; ic->str; ic++) - if (!strcasecmp(str, ic->str)) { - *codep = ic->code; - return; - } - show_usage("unknown ICMP6 unreachable code ``%s''", str); -} - -static void -add_port(cnt, ptr, off, port) - u_short *cnt, *ptr, off, port; -{ - if (off + *cnt >= IPV6_FW_MAX_PORTS) - errx(1, "too many ports (max is %d)", IPV6_FW_MAX_PORTS); - ptr[off+*cnt] = port; - (*cnt)++; -} - -static int -lookup_port(const char *arg, int test, int nodash) -{ - int val; - char *earg, buf[32]; - struct servent *s; - - snprintf(buf, sizeof(buf), "%s", arg); - buf[strcspn(arg, nodash ? "-," : ",")] = 0; - val = (int) strtoul(buf, &earg, 0); - if (!*buf || *earg) { - setservent(1); - if ((s = getservbyname(buf, NULL))) { - val = htons(s->s_port); - } else { - if (!test) { - errx(1, "unknown port ``%s''", arg); - } - val = -1; - } - } else { - if (val < 0 || val > 0xffff) { - if (!test) { - errx(1, "port ``%s'' out of range", arg); - } - val = -1; - } - } - return(val); -} - -int -fill_port(cnt, ptr, off, arg) - u_short *cnt, *ptr, off; - char *arg; -{ - char *s; - int initial_range = 0; - - s = arg + strcspn(arg, "-,"); /* first port name can't have a dash */ - if (*s == '-') { - *s++ = '\0'; - if (strchr(arg, ',')) - errx(1, "port range must be first in list"); - add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0x0000); - arg = s; - s = strchr(arg,','); - if (s) - *s++ = '\0'; - add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0xffff); - arg = s; - initial_range = 1; - } - while (arg != NULL) { - s = strchr(arg,','); - if (s) - *s++ = '\0'; - add_port(cnt, ptr, off, lookup_port(arg, 0, 0)); - arg = s; - } - return initial_range; -} - -void -fill_tcpflag(set, reset, vp) - u_char *set, *reset; - char **vp; -{ - char *p = *vp,*q; - u_char *d; - - while (p && *p) { - struct tpcflags { - char * name; - u_char value; - } flags[] = { - { "syn", IPV6_FW_TCPF_SYN }, - { "fin", IPV6_FW_TCPF_FIN }, - { "ack", IPV6_FW_TCPF_ACK }, - { "psh", IPV6_FW_TCPF_PSH }, - { "rst", IPV6_FW_TCPF_RST }, - { "urg", IPV6_FW_TCPF_URG } - }; - int i; - - if (*p == '!') { - p++; - d = reset; - } else { - d = set; - } - q = strchr(p, ','); - if (q) - *q++ = '\0'; - for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) - if (!strncmp(p, flags[i].name, strlen(p))) { - *d |= flags[i].value; - break; - } - if (i == sizeof(flags) / sizeof(flags[0])) - show_usage("invalid tcp flag ``%s''", p); - p = q; - } -} - -static void -fill_ip6opt(u_char *set, u_char *reset, char **vp) -{ - char *p = *vp,*q; - u_char *d; - - while (p && *p) { - if (*p == '!') { - p++; - d = reset; - } else { - d = set; - } - q = strchr(p, ','); - if (q) - *q++ = '\0'; - if (!strncmp(p,"hopopt",strlen(p))) *d |= IPV6_FW_IP6OPT_HOPOPT; - if (!strncmp(p,"route",strlen(p))) *d |= IPV6_FW_IP6OPT_ROUTE; - if (!strncmp(p,"frag",strlen(p))) *d |= IPV6_FW_IP6OPT_FRAG; - if (!strncmp(p,"esp",strlen(p))) *d |= IPV6_FW_IP6OPT_ESP; - if (!strncmp(p,"ah",strlen(p))) *d |= IPV6_FW_IP6OPT_AH; - if (!strncmp(p,"nonxt",strlen(p))) *d |= IPV6_FW_IP6OPT_NONXT; - if (!strncmp(p,"opts",strlen(p))) *d |= IPV6_FW_IP6OPT_OPTS; - p = q; - } -} - -void -fill_icmptypes(types, vp, fw_flg) - unsigned *types; - char **vp; - u_short *fw_flg; -{ - char *c = *vp; - - while (*c) - { - unsigned long icmptype; - - if ( *c == ',' ) - ++c; - - icmptype = strtoul(c, &c, 0); - - if ( *c != ',' && *c != '\0' ) - show_usage("invalid ICMP6 type"); - - if (icmptype >= IPV6_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8) - show_usage("ICMP6 type out of range"); - - types[icmptype / (sizeof(unsigned) * 8)] |= - 1U << (icmptype % (sizeof(unsigned) * 8)); - *fw_flg |= IPV6_FW_F_ICMPBIT; - } -} - -void -delete(ac,av) - int ac; - char **av; -{ - struct ip6_fw rule; - int i; - int exitval = 0; - - memset(&rule, 0, sizeof rule); - rule.version = IPV6_FW_CURRENT_API_VERSION; - - av++; ac--; - - /* Rule number */ - while (ac && isdigit(**av)) { - rule.fw_number = atoi(*av); av++; ac--; - i = setsockopt(s, IPPROTO_IPV6, IPV6_FW_DEL, &rule, sizeof rule); - if (i) { - exitval = 1; - warn("rule %u: setsockopt(%s)", rule.fw_number, "IPV6_FW_DEL"); - } - } - if (exitval != 0) - exit(exitval); -} - -static void -verify_interface(union ip6_fw_if *ifu) -{ - struct ifreq ifr; - - /* - * If a unit was specified, check for that exact interface. - * If a wildcard was specified, check for unit 0. - */ - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", - ifu->fu_via_if.name, - ifu->fu_via_if.unit == -1 ? 0 : ifu->fu_via_if.unit); - - if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) - warnx("warning: interface ``%s'' does not exist", ifr.ifr_name); -} - -static void -fill_iface(char *which, union ip6_fw_if *ifu, int *byname, int ac, char *arg) -{ - if (!ac) - show_usage("missing argument for ``%s''", which); - - /* Parse the interface or address */ - if (!strcmp(arg, "any")) { - ifu->fu_via_ip6 = in6addr_any; - *byname = 0; - } else if (!isdigit(*arg)) { - char *q; - - *byname = 1; - strncpy(ifu->fu_via_if.name, arg, sizeof(ifu->fu_via_if.name)); - ifu->fu_via_if.name[sizeof(ifu->fu_via_if.name) - 1] = '\0'; - for (q = ifu->fu_via_if.name; - *q && !isdigit(*q) && *q != '*'; q++) - continue; - ifu->fu_via_if.unit = (*q == '*') ? -1 : atoi(q); - *q = '\0'; - verify_interface(ifu); - } else if (inet_pton(AF_INET6, arg, &ifu->fu_via_ip6) != 1) { - show_usage("bad ip6 address ``%s''", arg); - } else - *byname = 0; -} - -static void -add(ac,av) - int ac; - char **av; -{ - struct ip6_fw rule; - int i; - u_char proto; - struct protoent *pe; - int saw_xmrc = 0, saw_via = 0; - - memset(&rule, 0, sizeof rule); - rule.version = IPV6_FW_CURRENT_API_VERSION; - - av++; ac--; - - /* Rule number */ - if (ac && isdigit(**av)) { - rule.fw_number = atoi(*av); av++; ac--; - } - - /* Action */ - if (ac == 0) - show_usage("missing action"); - if (!strncmp(*av,"accept",strlen(*av)) - || !strncmp(*av,"pass",strlen(*av)) - || !strncmp(*av,"allow",strlen(*av)) - || !strncmp(*av,"permit",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_ACCEPT; av++; ac--; - } else if (!strncmp(*av,"count",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_COUNT; av++; ac--; - } -#if 0 - else if (!strncmp(*av,"divert",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_DIVERT; av++; ac--; - if (!ac) - show_usage("missing divert port"); - rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--; - if (rule.fw_divert_port == 0) { - struct servent *s; - setservent(1); - s = getservbyname(av[-1], "divert"); - if (s != NULL) - rule.fw_divert_port = ntohs(s->s_port); - else - show_usage("illegal divert port"); - } - } else if (!strncmp(*av,"tee",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_TEE; av++; ac--; - if (!ac) - show_usage("missing divert port"); - rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--; - if (rule.fw_divert_port == 0) { - struct servent *s; - setservent(1); - s = getservbyname(av[-1], "divert"); - if (s != NULL) - rule.fw_divert_port = ntohs(s->s_port); - else - show_usage("illegal divert port"); - } - } -#endif - else if (!strncmp(*av,"skipto",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_SKIPTO; av++; ac--; - if (!ac) - show_usage("missing skipto rule number"); - rule.fw_skipto_rule = strtoul(*av, NULL, 0); av++; ac--; - } else if ((!strncmp(*av,"deny",strlen(*av)) - || !strncmp(*av,"drop",strlen(*av)))) { - rule.fw_flg |= IPV6_FW_F_DENY; av++; ac--; - } else if (!strncmp(*av,"reject",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_REJECT; av++; ac--; - rule.fw_reject_code = ICMP6_DST_UNREACH_NOROUTE; - } else if (!strncmp(*av,"reset",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_REJECT; av++; ac--; - rule.fw_reject_code = IPV6_FW_REJECT_RST; /* check TCP later */ - } else if (!strncmp(*av,"unreach",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_REJECT; av++; ac--; - fill_reject_code6(&rule.fw_reject_code, *av); av++; ac--; - } else { - show_usage("invalid action ``%s''", *av); - } - - /* [log] */ - if (ac && !strncmp(*av,"log",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_PRN; av++; ac--; - } - - /* protocol */ - if (ac == 0) - show_usage("missing protocol"); - if ((proto = atoi(*av)) > 0) { - rule.fw_prot = proto; av++; ac--; - } else if (!strncmp(*av,"all",strlen(*av))) { - rule.fw_prot = IPPROTO_IPV6; av++; ac--; - } else if ((pe = getprotobyname(*av)) != NULL) { - rule.fw_prot = pe->p_proto; av++; ac--; - } else { - show_usage("invalid protocol ``%s''", *av); - } - - if (rule.fw_prot != IPPROTO_TCP - && (rule.fw_flg & IPV6_FW_F_COMMAND) == IPV6_FW_F_REJECT - && rule.fw_reject_code == IPV6_FW_REJECT_RST) - show_usage("``reset'' is only valid for tcp packets"); - - /* from */ - if (ac && !strncmp(*av,"from",strlen(*av))) { av++; ac--; } - else - show_usage("missing ``from''"); - - if (ac && !strncmp(*av,"not",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_INVSRC; - av++; ac--; - } - if (!ac) - show_usage("missing arguments"); - - fill_ip6(&rule.fw_src, &rule.fw_smsk, &ac, &av); - - if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) { - u_short nports = 0; - - if (fill_port(&nports, rule.fw_pts, 0, *av)) - rule.fw_flg |= IPV6_FW_F_SRNG; - IPV6_FW_SETNSRCP(&rule, nports); - av++; ac--; - } - - /* to */ - if (ac && !strncmp(*av,"to",strlen(*av))) { av++; ac--; } - else - show_usage("missing ``to''"); - - if (ac && !strncmp(*av,"not",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_INVDST; - av++; ac--; - } - if (!ac) - show_usage("missing arguments"); - - fill_ip6(&rule.fw_dst, &rule.fw_dmsk, &ac, &av); - - if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) { - u_short nports = 0; - - if (fill_port(&nports, - rule.fw_pts, IPV6_FW_GETNSRCP(&rule), *av)) - rule.fw_flg |= IPV6_FW_F_DRNG; - IPV6_FW_SETNDSTP(&rule, nports); - av++; ac--; - } - - if ((rule.fw_prot != IPPROTO_TCP) && (rule.fw_prot != IPPROTO_UDP) - && (IPV6_FW_GETNSRCP(&rule) || IPV6_FW_GETNDSTP(&rule))) { - show_usage("only TCP and UDP protocols are valid" - " with port specifications"); - } - - while (ac) { - if (!strncmp(*av,"in",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_IN; - av++; ac--; continue; - } - if (!strncmp(*av,"out",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_OUT; - av++; ac--; continue; - } - if (ac && !strncmp(*av,"xmit",strlen(*av))) { - union ip6_fw_if ifu; - int byname; - - if (saw_via) { -badviacombo: - show_usage("``via'' is incompatible" - " with ``xmit'' and ``recv''"); - } - saw_xmrc = 1; - av++; ac--; - fill_iface("xmit", &ifu, &byname, ac, *av); - rule.fw_out_if = ifu; - rule.fw_flg |= IPV6_FW_F_OIFACE; - if (byname) - rule.fw_flg |= IPV6_FW_F_OIFNAME; - av++; ac--; continue; - } - if (ac && !strncmp(*av,"recv",strlen(*av))) { - union ip6_fw_if ifu; - int byname; - - if (saw_via) - goto badviacombo; - saw_xmrc = 1; - av++; ac--; - fill_iface("recv", &ifu, &byname, ac, *av); - rule.fw_in_if = ifu; - rule.fw_flg |= IPV6_FW_F_IIFACE; - if (byname) - rule.fw_flg |= IPV6_FW_F_IIFNAME; - av++; ac--; continue; - } - if (ac && !strncmp(*av,"via",strlen(*av))) { - union ip6_fw_if ifu; - int byname = 0; - - if (saw_xmrc) - goto badviacombo; - saw_via = 1; - av++; ac--; - fill_iface("via", &ifu, &byname, ac, *av); - rule.fw_out_if = rule.fw_in_if = ifu; - if (byname) - rule.fw_flg |= - (IPV6_FW_F_IIFNAME | IPV6_FW_F_OIFNAME); - av++; ac--; continue; - } - if (!strncmp(*av,"fragment",strlen(*av))) { - rule.fw_flg |= IPV6_FW_F_FRAG; - av++; ac--; continue; - } - if (!strncmp(*av,"ipv6options",strlen(*av))) { - av++; ac--; - if (!ac) - show_usage("missing argument" - " for ``ipv6options''"); - fill_ip6opt(&rule.fw_ip6opt, &rule.fw_ip6nopt, av); - av++; ac--; continue; - } - if (rule.fw_prot == IPPROTO_TCP) { - if (!strncmp(*av,"established",strlen(*av))) { - rule.fw_ipflg |= IPV6_FW_IF_TCPEST; - av++; ac--; continue; - } - if (!strncmp(*av,"setup",strlen(*av))) { - rule.fw_tcpf |= IPV6_FW_TCPF_SYN; - rule.fw_tcpnf |= IPV6_FW_TCPF_ACK; - av++; ac--; continue; - } - if (!strncmp(*av,"tcpflags",strlen(*av))) { - av++; ac--; - if (!ac) - show_usage("missing argument" - " for ``tcpflags''"); - fill_tcpflag(&rule.fw_tcpf, &rule.fw_tcpnf, av); - av++; ac--; continue; - } - } - if (rule.fw_prot == IPPROTO_ICMPV6) { - if (!strncmp(*av,"icmptypes",strlen(*av))) { - av++; ac--; - if (!ac) - show_usage("missing argument" - " for ``icmptypes''"); - fill_icmptypes(rule.fw_icmp6types, - av, &rule.fw_flg); - av++; ac--; continue; - } - } - show_usage("unknown argument ``%s''", *av); - } - - /* No direction specified -> do both directions */ - if (!(rule.fw_flg & (IPV6_FW_F_OUT|IPV6_FW_F_IN))) - rule.fw_flg |= (IPV6_FW_F_OUT|IPV6_FW_F_IN); - - /* Sanity check interface check, but handle "via" case separately */ - if (saw_via) { - if (rule.fw_flg & IPV6_FW_F_IN) - rule.fw_flg |= IPV6_FW_F_IIFACE; - if (rule.fw_flg & IPV6_FW_F_OUT) - rule.fw_flg |= IPV6_FW_F_OIFACE; - } else if ((rule.fw_flg & IPV6_FW_F_OIFACE) && (rule.fw_flg & IPV6_FW_F_IN)) - show_usage("can't check xmit interface of incoming packets"); - - /* frag may not be used in conjunction with ports or TCP flags */ - if (rule.fw_flg & IPV6_FW_F_FRAG) { - if (rule.fw_tcpf || rule.fw_tcpnf) - show_usage("can't mix 'frag' and tcpflags"); - - if (rule.fw_nports) - show_usage("can't mix 'frag' and port specifications"); - } - - i = setsockopt(s, IPPROTO_IPV6, IPV6_FW_ADD, &rule, sizeof rule); - if (i) - err(EX_UNAVAILABLE, "setsockopt(%s)", "IPV6_FW_ADD"); - if (!do_quiet) - show_ip6fw(&rule); -} - -static void -zero (ac, av) - int ac; - char **av; -{ - struct ip6_fw rule; - - av++; ac--; - memset(&rule, 0, sizeof rule); - rule.version = IPV6_FW_CURRENT_API_VERSION; - - if (!ac) { - /* clear all entries */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_FW_ZERO, &rule, sizeof rule) < 0) - err(EX_UNAVAILABLE, "setsockopt(%s)", "IPV6_FW_ZERO"); - if (!do_quiet) - printf("Accounting cleared.\n"); - } else { - int failed = 0; - - while (ac) { - /* Rule number */ - if (isdigit(**av)) { - rule.fw_number = atoi(*av); av++; ac--; - if (setsockopt(s, IPPROTO_IPV6, - IPV6_FW_ZERO, &rule, sizeof rule)) { - warn("rule %u: setsockopt(%s)", rule.fw_number, - "IPV6_FW_ZERO"); - failed = 1; - } - else if (!do_quiet) - printf("Entry %d cleared\n", - rule.fw_number); - } else - show_usage("invalid rule number ``%s''", *av); - } - if (failed != 0) - exit(failed); - } -} - -int -ip6fw_main(ac,av) - int ac; - char **av; -{ - int ch; - extern int optind; - - /* init optind to 1 */ - optind = 1; - - if ( ac == 1 ) { - show_usage(NULL); - } - - /* Set the force flag for non-interactive processes */ - do_force = !isatty(STDIN_FILENO); - - while ((ch = getopt(ac, av ,"afqtN")) != -1) - switch(ch) { - case 'a': - do_acct=1; - break; - case 'f': - do_force=1; - break; - case 'q': - do_quiet=1; - break; - case 't': - do_time=1; - break; - case 'N': - do_resolv=1; - break; - default: - show_usage(NULL); - } - - ac -= optind; - if (*(av+=optind)==NULL) { - show_usage("Bad arguments"); - } - - if (!strncmp(*av, "add", strlen(*av))) { - add(ac,av); - } else if (!strncmp(*av, "delete", strlen(*av))) { - delete(ac,av); - } else if (!strncmp(*av, "flush", strlen(*av))) { - int do_flush = 0; - - if ( do_force || do_quiet ) - do_flush = 1; - else { - int c; - - /* Ask the user */ - printf("Are you sure? [yn] "); - do { - fflush(stdout); - c = toupper(getc(stdin)); - while (c != '\n' && getc(stdin) != '\n') - if (feof(stdin)) - return (0); - } while (c != 'Y' && c != 'N'); - printf("\n"); - if (c == 'Y') - do_flush = 1; - } - if ( do_flush ) { - struct ip6_fw rule; - - memset(&rule, 0, sizeof rule); - rule.version = IPV6_FW_CURRENT_API_VERSION; - if (setsockopt(s, IPPROTO_IPV6, IPV6_FW_FLUSH, &rule, sizeof rule) < 0) - err(EX_UNAVAILABLE, "setsockopt(%s)", "IPV6_FW_FLUSH"); - if (!do_quiet) - printf("Flushed all rules.\n"); - } - } else if (!strncmp(*av, "zero", strlen(*av))) { - zero(ac,av); - } else if (!strncmp(*av, "print", strlen(*av))) { - list(--ac,++av); - } else if (!strncmp(*av, "list", strlen(*av))) { - list(--ac,++av); - } else if (!strncmp(*av, "show", strlen(*av))) { - do_acct++; - list(--ac,++av); - } else { - show_usage("Bad arguments"); - } - return 0; -} - -int -main(ac, av) - int ac; - char **av; -{ -#define MAX_ARGS 32 -#define WHITESP " \t\f\v\n\r" - char buf[BUFSIZ]; - char *a, *p, *args[MAX_ARGS], *cmd = NULL; - char linename[16]; - int i, c, lineno, qflag, pflag, status; - FILE *f = NULL; - pid_t preproc = 0; - - s = socket( AF_INET6, SOCK_RAW, IPPROTO_RAW ); - if ( s < 0 ) - err(EX_UNAVAILABLE, "socket"); - - setbuf(stdout,0); - - /* - * Only interpret the last command line argument as a file to - * be preprocessed if it is specified as an absolute pathname. - */ - - if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) { - qflag = pflag = i = 0; - lineno = 0; - - while ((c = getopt(ac, av, "D:U:p:q")) != -1) - switch(c) { - case 'D': - if (!pflag) - errx(EX_USAGE, "-D requires -p"); - if (i > MAX_ARGS - 2) - errx(EX_USAGE, - "too many -D or -U options"); - args[i++] = "-D"; - args[i++] = optarg; - break; - - case 'U': - if (!pflag) - errx(EX_USAGE, "-U requires -p"); - if (i > MAX_ARGS - 2) - errx(EX_USAGE, - "too many -D or -U options"); - args[i++] = "-U"; - args[i++] = optarg; - break; - - case 'p': - pflag = 1; - cmd = optarg; - args[0] = cmd; - i = 1; - break; - - case 'q': - qflag = 1; - break; - - default: - show_usage(NULL); - } - - av += optind; - ac -= optind; - if (ac != 1) - show_usage("extraneous filename arguments"); - - if ((f = fopen(av[0], "r")) == NULL) - err(EX_UNAVAILABLE, "fopen: %s", av[0]); - - if (pflag) { - /* pipe through preprocessor (cpp or m4) */ - int pipedes[2]; - - args[i] = 0; - - if (pipe(pipedes) == -1) - err(EX_OSERR, "cannot create pipe"); - - switch((preproc = fork())) { - case -1: - err(EX_OSERR, "cannot fork"); - - case 0: - /* child */ - if (dup2(fileno(f), 0) == -1 || - dup2(pipedes[1], 1) == -1) - err(EX_OSERR, "dup2()"); - fclose(f); - close(pipedes[1]); - close(pipedes[0]); - execvp(cmd, args); - err(EX_OSERR, "execvp(%s) failed", cmd); - - default: - /* parent */ - fclose(f); - close(pipedes[1]); - if ((f = fdopen(pipedes[0], "r")) == NULL) { - int savederrno = errno; - - (void)kill(preproc, SIGTERM); - errno = savederrno; - err(EX_OSERR, "fdopen()"); - } - } - } - - while (fgets(buf, BUFSIZ, f)) { - lineno++; - snprintf(linename, sizeof(linename), "Line %d", lineno); - args[0] = linename; - - if (*buf == '#') - continue; - if ((p = strchr(buf, '#')) != NULL) - *p = '\0'; - i=1; - if (qflag) args[i++]="-q"; - for (a = strtok(buf, WHITESP); - a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++) - args[i] = a; - if (i == (qflag? 2: 1)) - continue; - if (i == MAX_ARGS) - errx(EX_USAGE, "%s: too many arguments", linename); - args[i] = NULL; - - ip6fw_main(i, args); - } - fclose(f); - if (pflag) { - if (waitpid(preproc, &status, 0) != -1) { - if (WIFEXITED(status)) { - if (WEXITSTATUS(status) != EX_OK) - errx(EX_UNAVAILABLE, - "preprocessor exited with status %d", - WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - errx(EX_UNAVAILABLE, - "preprocessor exited with signal %d", - WTERMSIG(status)); - } - } - } - } else - ip6fw_main(ac,av); - return 0; -} diff --git a/ipfw.tproj/ipfw.8 b/ipfw.tproj/ipfw.8 deleted file mode 100644 index 71e3aed..0000000 --- a/ipfw.tproj/ipfw.8 +++ /dev/null @@ -1,11 +0,0 @@ -.Dd September 27, 2012 -.Dt IPFW 8 -.Os Darwin -.Sh NAME -.Nm ipfw -.Sh DESCRIPTION -This utility is -.Cm DEPRECATED. -Please use -.Xr pfctl 8 -instead. diff --git a/ipfw.tproj/ipfw2.c b/ipfw.tproj/ipfw2.c deleted file mode 100644 index c6c35af..0000000 --- a/ipfw.tproj/ipfw2.c +++ /dev/null @@ -1,4064 +0,0 @@ -/* - * Copyright (c) 2002-2009 Apple Inc. All rights reserved. - * - * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the License - * may not be used to create, or enable the creation or redistribution of, - * unlawful or unlicensed copies of an Apple operating system, or to - * circumvent, violate, or enable the circumvention or violation of, any - * terms of an Apple operating system software license agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ - */ - -/* - * Copyright (c) 2002-2003 Luigi Rizzo - * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp - * Copyright (c) 1994 Ugen J.S.Antsilevich - * - * Idea and grammar partially left from: - * Copyright (c) 1993 Daniel Boulet - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. - * - * NEW command line interface for IP firewall facility - * - * $FreeBSD: /repoman/r/ncvs/src/sbin/ipfw/ipfw2.c,v 1.4.2.18 2003/09/15 10:27:03 luigi Exp $ - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#define IPFW2 -#include -#undef IPFW2 -#include /* def. of struct route */ -#include -#include -#include - -int - do_resolv, /* Would try to resolve all */ - do_time, /* Show time stamps */ - do_quiet, /* Be quiet in add and flush */ - do_pipe, /* this cmd refers to a pipe */ - do_sort, /* field to sort results (0 = no) */ - do_dynamic, /* display dynamic rules */ - do_expired, /* display expired dynamic rules */ - do_compact, /* show rules in compact mode */ - show_sets, /* display rule sets */ - test_only, /* only check syntax */ - verbose; - -#define IP_MASK_ALL 0xffffffff - -/* - * _s_x is a structure that stores a string <-> token pairs, used in - * various places in the parser. Entries are stored in arrays, - * with an entry with s=NULL as terminator. - * The search routines are match_token() and match_value(). - * Often, an element with x=0 contains an error string. - * - */ -struct _s_x { - char const *s; - int x; -}; - -static struct _s_x f_tcpflags[] = { - { "syn", TH_SYN }, - { "fin", TH_FIN }, - { "ack", TH_ACK }, - { "psh", TH_PUSH }, - { "rst", TH_RST }, - { "urg", TH_URG }, - { "tcp flag", 0 }, - { NULL, 0 } -}; - -static struct _s_x f_tcpopts[] = { - { "mss", IP_FW_TCPOPT_MSS }, - { "maxseg", IP_FW_TCPOPT_MSS }, - { "window", IP_FW_TCPOPT_WINDOW }, - { "sack", IP_FW_TCPOPT_SACK }, - { "ts", IP_FW_TCPOPT_TS }, - { "timestamp", IP_FW_TCPOPT_TS }, - { "cc", IP_FW_TCPOPT_CC }, - { "tcp option", 0 }, - { NULL, 0 } -}; - -/* - * IP options span the range 0 to 255 so we need to remap them - * (though in fact only the low 5 bits are significant). - */ -static struct _s_x f_ipopts[] = { - { "ssrr", IP_FW_IPOPT_SSRR}, - { "lsrr", IP_FW_IPOPT_LSRR}, - { "rr", IP_FW_IPOPT_RR}, - { "ts", IP_FW_IPOPT_TS}, - { "ip option", 0 }, - { NULL, 0 } -}; - -static struct _s_x f_iptos[] = { - { "lowdelay", IPTOS_LOWDELAY}, - { "throughput", IPTOS_THROUGHPUT}, - { "reliability", IPTOS_RELIABILITY}, - { "mincost", IPTOS_MINCOST}, - { "congestion", IPTOS_CE}, - { "ecntransport", IPTOS_ECT}, - { "ip tos option", 0}, - { NULL, 0 } -}; - -static struct _s_x limit_masks[] = { - {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, - {"src-addr", DYN_SRC_ADDR}, - {"src-port", DYN_SRC_PORT}, - {"dst-addr", DYN_DST_ADDR}, - {"dst-port", DYN_DST_PORT}, - {NULL, 0} -}; - -/* - * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines - * This is only used in this code. - */ -#define IPPROTO_ETHERTYPE 0x1000 -static struct _s_x ether_types[] = { - /* - * Note, we cannot use "-:&/" in the names because they are field - * separators in the type specifications. Also, we use s = NULL as - * end-delimiter, because a type of 0 can be legal. - */ - { "ip", 0x0800 }, - { "ipv4", 0x0800 }, - { "ipv6", 0x86dd }, - { "arp", 0x0806 }, - { "rarp", 0x8035 }, - { "vlan", 0x8100 }, - { "loop", 0x9000 }, - { "trail", 0x1000 }, - { "at", 0x809b }, - { "atalk", 0x809b }, - { "aarp", 0x80f3 }, - { "pppoe_disc", 0x8863 }, - { "pppoe_sess", 0x8864 }, - { "ipx_8022", 0x00E0 }, - { "ipx_8023", 0x0000 }, - { "ipx_ii", 0x8137 }, - { "ipx_snap", 0x8137 }, - { "ipx", 0x8137 }, - { "ns", 0x0600 }, - { NULL, 0 } -}; - -static struct _s_x exception_types[] = { - { "to", 1}, - { "dst", 2}, - { "in", 3}, - { "out", 4}, - { "xmit", 5}, - { "recv", 6}, - { "via", 7}, - { "src", 8}, - { NULL, 0} -}; - -static void show_usage(void); - -enum tokens { - TOK_NULL=0, - - TOK_OR, - TOK_NOT, - TOK_STARTBRACE, - TOK_ENDBRACE, - - TOK_ACCEPT, - TOK_COUNT, - TOK_PIPE, - TOK_QUEUE, - TOK_DIVERT, - TOK_TEE, - TOK_FORWARD, - TOK_SKIPTO, - TOK_DENY, - TOK_REJECT, - TOK_RESET, - TOK_UNREACH, - TOK_CHECKSTATE, - - TOK_UID, - TOK_GID, - TOK_IN, - TOK_LIMIT, - TOK_KEEPSTATE, - TOK_LAYER2, - TOK_OUT, - TOK_XMIT, - TOK_RECV, - TOK_VIA, - TOK_FRAG, - TOK_IPOPTS, - TOK_IPLEN, - TOK_IPID, - TOK_IPPRECEDENCE, - TOK_IPTOS, - TOK_IPTTL, - TOK_IPVER, - TOK_ESTAB, - TOK_SETUP, - TOK_TCPFLAGS, - TOK_TCPOPTS, - TOK_TCPSEQ, - TOK_TCPACK, - TOK_TCPWIN, - TOK_ICMPTYPES, - TOK_MAC, - TOK_MACTYPE, - TOK_VERREVPATH, - TOK_IPSEC, - TOK_COMMENT, - - TOK_PLR, - TOK_NOERROR, - TOK_BUCKETS, - TOK_DSTIP, - TOK_SRCIP, - TOK_DSTPORT, - TOK_SRCPORT, - TOK_ALL, - TOK_MASK, - TOK_BW, - TOK_DELAY, - TOK_RED, - TOK_GRED, - TOK_DROPTAIL, - TOK_PROTO, - TOK_WEIGHT, -}; - -struct _s_x dummynet_params[] = { - { "plr", TOK_PLR }, - { "noerror", TOK_NOERROR }, - { "buckets", TOK_BUCKETS }, - { "dst-ip", TOK_DSTIP }, - { "src-ip", TOK_SRCIP }, - { "dst-port", TOK_DSTPORT }, - { "src-port", TOK_SRCPORT }, - { "proto", TOK_PROTO }, - { "weight", TOK_WEIGHT }, - { "all", TOK_ALL }, - { "mask", TOK_MASK }, - { "droptail", TOK_DROPTAIL }, - { "red", TOK_RED }, - { "gred", TOK_GRED }, - { "bw", TOK_BW }, - { "bandwidth", TOK_BW }, - { "delay", TOK_DELAY }, - { "pipe", TOK_PIPE }, - { "queue", TOK_QUEUE }, - { "dummynet-params", TOK_NULL }, - { NULL, 0 } /* terminator */ -}; - -struct _s_x rule_actions[] = { - { "accept", TOK_ACCEPT }, - { "pass", TOK_ACCEPT }, - { "allow", TOK_ACCEPT }, - { "permit", TOK_ACCEPT }, - { "count", TOK_COUNT }, - { "pipe", TOK_PIPE }, - { "queue", TOK_QUEUE }, - { "divert", TOK_DIVERT }, - { "tee", TOK_TEE }, - { "fwd", TOK_FORWARD }, - { "forward", TOK_FORWARD }, - { "skipto", TOK_SKIPTO }, - { "deny", TOK_DENY }, - { "drop", TOK_DENY }, - { "reject", TOK_REJECT }, - { "reset", TOK_RESET }, - { "unreach", TOK_UNREACH }, - { "check-state", TOK_CHECKSTATE }, - { "//", TOK_COMMENT }, - { NULL, 0 } /* terminator */ -}; - -struct _s_x rule_options[] = { - { "uid", TOK_UID }, - { "gid", TOK_GID }, - { "in", TOK_IN }, - { "limit", TOK_LIMIT }, - { "keep-state", TOK_KEEPSTATE }, - { "bridged", TOK_LAYER2 }, - { "layer2", TOK_LAYER2 }, - { "out", TOK_OUT }, - { "xmit", TOK_XMIT }, - { "recv", TOK_RECV }, - { "via", TOK_VIA }, - { "fragment", TOK_FRAG }, - { "frag", TOK_FRAG }, - { "ipoptions", TOK_IPOPTS }, - { "ipopts", TOK_IPOPTS }, - { "iplen", TOK_IPLEN }, - { "ipid", TOK_IPID }, - { "ipprecedence", TOK_IPPRECEDENCE }, - { "iptos", TOK_IPTOS }, - { "ipttl", TOK_IPTTL }, - { "ipversion", TOK_IPVER }, - { "ipver", TOK_IPVER }, - { "estab", TOK_ESTAB }, - { "established", TOK_ESTAB }, - { "setup", TOK_SETUP }, - { "tcpflags", TOK_TCPFLAGS }, - { "tcpflgs", TOK_TCPFLAGS }, - { "tcpoptions", TOK_TCPOPTS }, - { "tcpopts", TOK_TCPOPTS }, - { "tcpseq", TOK_TCPSEQ }, - { "tcpack", TOK_TCPACK }, - { "tcpwin", TOK_TCPWIN }, - { "icmptype", TOK_ICMPTYPES }, - { "icmptypes", TOK_ICMPTYPES }, - { "dst-ip", TOK_DSTIP }, - { "src-ip", TOK_SRCIP }, - { "dst-port", TOK_DSTPORT }, - { "src-port", TOK_SRCPORT }, - { "proto", TOK_PROTO }, - { "MAC", TOK_MAC }, - { "mac", TOK_MAC }, - { "mac-type", TOK_MACTYPE }, - { "verrevpath", TOK_VERREVPATH }, - { "ipsec", TOK_IPSEC }, - { "//", TOK_COMMENT }, - - { "not", TOK_NOT }, /* pseudo option */ - { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ - { "or", TOK_OR }, /* pseudo option */ - { "|", /* escape */ TOK_OR }, /* pseudo option */ - { "{", TOK_STARTBRACE }, /* pseudo option */ - { "(", TOK_STARTBRACE }, /* pseudo option */ - { "}", TOK_ENDBRACE }, /* pseudo option */ - { ")", TOK_ENDBRACE }, /* pseudo option */ - { NULL, 0 } /* terminator */ -}; - -static __inline uint64_t -align_uint64(uint64_t *pll) { - uint64_t ret; - - bcopy (pll, &ret, sizeof(ret)); - return ret; -}; - -/* - * conditionally runs the command. - */ -static int -do_cmd(int optname, void *optval, uintptr_t optlen) -{ - static int s = -1; /* the socket */ - int i; - - if (test_only) - return 0; - - if (s == -1) - s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (s < 0) - err(EX_UNAVAILABLE, "socket"); - - switch (optname) { - case IP_FW_GET: - case IP_FW_FLUSH: - case IP_FW_ADD: - case IP_FW_DEL: - case IP_FW_ZERO: - case IP_FW_RESETLOG: - ((struct ip_fw *)optval)->version = IP_FW_CURRENT_API_VERSION; - default: - break; - } - - if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || - optname == IP_FW_ADD) - i = getsockopt(s, IPPROTO_IP, optname, optval, - (socklen_t *)optlen); - else - i = setsockopt(s, IPPROTO_IP, optname, optval, optlen); - return i; -} - -/** - * match_token takes a table and a string, returns the value associated - * with the string (-1 in case of failure). - */ -static int -match_token(struct _s_x *table, char *string) -{ - struct _s_x *pt; - uint i = strlen(string); - - for (pt = table ; i && pt->s != NULL ; pt++) - if (strlen(pt->s) == i && !bcmp(string, pt->s, i)) - return pt->x; - return -1; -}; - -/** - * match_value takes a table and a value, returns the string associated - * with the value (NULL in case of failure). - */ -static char const * -match_value(struct _s_x *p, int value) -{ - for (; p->s != NULL; p++) - if (p->x == value) - return p->s; - return NULL; -} - -/* - * prints one port, symbolic or numeric - */ -static void -print_port(int proto, uint16_t port) -{ - - if (proto == IPPROTO_ETHERTYPE) { - char const *s; - - if (do_resolv && (s = match_value(ether_types, port)) ) - printf("%s", s); - else - printf("0x%04x", port); - } else { - struct servent *se = NULL; - if (do_resolv) { - struct protoent *pe = getprotobynumber(proto); - - se = getservbyport(htons(port), pe ? pe->p_name : NULL); - } - if (se) - printf("%s", se->s_name); - else - printf("%d", port); - } -} - -struct _s_x _port_name[] = { - {"dst-port", O_IP_DSTPORT}, - {"src-port", O_IP_SRCPORT}, - {"ipid", O_IPID}, - {"iplen", O_IPLEN}, - {"ipttl", O_IPTTL}, - {"mac-type", O_MAC_TYPE}, - {NULL, 0} -}; - -/* - * Print the values in a list 16-bit items of the types above. - * XXX todo: add support for mask. - */ -static void -print_newports(ipfw_insn_u16 *cmd, int proto, int opcode) -{ - uint16_t *p = cmd->ports; - int i; - char const *sep; - - if (cmd->o.len & F_NOT) - printf(" not"); - if (opcode != 0) { - sep = match_value(_port_name, opcode); - if (sep == NULL) - sep = "???"; - printf (" %s", sep); - } - sep = " "; - for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { - printf("%s", sep); - print_port(proto, p[0]); - if (p[0] != p[1]) { - printf("-"); - print_port(proto, p[1]); - } - sep = ","; - } -} - -/* - * Like strtol, but also translates service names into port numbers - * for some protocols. - * In particular: - * proto == -1 disables the protocol check; - * proto == IPPROTO_ETHERTYPE looks up an internal table - * proto == matches the values there. - * Returns *end == s in case the parameter is not found. - */ -static int -strtoport(char *s, char **end, int base, int proto) -{ - char *p, *buf; - char *s1; - int i; - - *end = s; /* default - not found */ - if (*s == '\0') - return 0; /* not found */ - - if (isdigit(*s)) - return strtol(s, end, base); - - /* - * find separator. '\\' escapes the next char. - */ - for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) - if (*s1 == '\\' && s1[1] != '\0') - s1++; - - buf = malloc(s1 - s + 1); - if (buf == NULL) - return 0; - - /* - * copy into a buffer skipping backslashes - */ - for (p = s, i = 0; p != s1 ; p++) - if (*p != '\\') - buf[i++] = *p; - buf[i++] = '\0'; - - if ( match_token( exception_types, buf) != -1 ){ - free(buf); - return 0; - } - - if (proto == IPPROTO_ETHERTYPE) { - i = match_token(ether_types, buf); - free(buf); - if (i != -1) { /* found */ - *end = s1; - return i; - } - } else { - struct protoent *pe = NULL; - struct servent *se; - - if (proto != 0) - pe = getprotobynumber(proto); - setservent(1); - se = getservbyname(buf, pe ? pe->p_name : NULL); - free(buf); - if (se != NULL) { - *end = s1; - return ntohs(se->s_port); - } - } - return 0; /* not found */ -} - -/* - * Fill the body of the command with the list of port ranges. - */ -static int -fill_newports(ipfw_insn_u16 *cmd, char *av, int proto) -{ - uint16_t a, b, *p = cmd->ports; - int i = 0; - char *s = av; - - while (*s) { - a = strtoport(av, &s, 0, proto); - if (s == av) /* no parameter */ - break; - if (*s == '-') { /* a range */ - av = s+1; - b = strtoport(av, &s, 0, proto); - if (s == av) /* no parameter */ - break; - p[0] = a; - p[1] = b; - } else if (*s == ',' || *s == '\0' ) - p[0] = p[1] = a; - else /* invalid separator */ - errx(EX_DATAERR, "invalid separator <%c> in <%s>", - *s, av); - i++; - p += 2; - av = s+1; - } - if (i > 0) { - if (i+1 > F_LEN_MASK) - errx(EX_DATAERR, "too many ports/ranges"); - cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */ - } - return i; -} - -static struct _s_x icmpcodes[] = { - { "net", ICMP_UNREACH_NET }, - { "host", ICMP_UNREACH_HOST }, - { "protocol", ICMP_UNREACH_PROTOCOL }, - { "port", ICMP_UNREACH_PORT }, - { "needfrag", ICMP_UNREACH_NEEDFRAG }, - { "srcfail", ICMP_UNREACH_SRCFAIL }, - { "net-unknown", ICMP_UNREACH_NET_UNKNOWN }, - { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN }, - { "isolated", ICMP_UNREACH_ISOLATED }, - { "net-prohib", ICMP_UNREACH_NET_PROHIB }, - { "host-prohib", ICMP_UNREACH_HOST_PROHIB }, - { "tosnet", ICMP_UNREACH_TOSNET }, - { "toshost", ICMP_UNREACH_TOSHOST }, - { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB }, - { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE }, - { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF }, - { NULL, 0 } -}; - -static void -fill_reject_code(u_short *codep, char *str) -{ - int val; - char *s; - - val = strtoul(str, &s, 0); - if (s == str || *s != '\0' || val >= 0x100) - val = match_token(icmpcodes, str); - if (val < 0) - errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); - *codep = val; - return; -} - -static void -print_reject_code(uint16_t code) -{ - char const *s = match_value(icmpcodes, code); - - if (s != NULL) - printf("unreach %s", s); - else - printf("unreach %u", code); -} - -/* - * Returns the number of bits set (from left) in a contiguous bitmask, - * or -1 if the mask is not contiguous. - * XXX this needs a proper fix. - * This effectively works on masks in big-endian (network) format. - * when compiled on little endian architectures. - * - * First bit is bit 7 of the first byte -- note, for MAC addresses, - * the first bit on the wire is bit 0 of the first byte. - * len is the max length in bits. - */ -static int -contigmask(uint8_t *p, int len) -{ - int i, n; - - for (i=0; iarg1 & 0xff; - uint8_t clear = (cmd->arg1 >> 8) & 0xff; - - if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { - printf(" setup"); - return; - } - - printf(" %s ", name); - for (i=0; list[i].x != 0; i++) { - if (set & list[i].x) { - set &= ~list[i].x; - printf("%s%s", comma, list[i].s); - comma = ","; - } - if (clear & list[i].x) { - clear &= ~list[i].x; - printf("%s!%s", comma, list[i].s); - comma = ","; - } - } -} - -/* - * Print the ip address contained in a command. - */ -static void -print_ip(ipfw_insn_ip *cmd, char const *s) -{ - struct hostent *he = NULL; - int len = F_LEN((ipfw_insn *)cmd); - uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; - - printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); - - if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { - printf("me"); - return; - } - if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { - uint32_t x, *map = (uint32_t *)&(cmd->mask); - int i, j; - char comma = '{'; - - x = cmd->o.arg1 - 1; - x = htonl( ~x ); - cmd->addr.s_addr = htonl(cmd->addr.s_addr); - printf("%s/%d", inet_ntoa(cmd->addr), - contigmask((uint8_t *)&x, 32)); - x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); - x &= 0xff; /* base */ - /* - * Print bits and ranges. - * Locate first bit set (i), then locate first bit unset (j). - * If we have 3+ consecutive bits set, then print them as a - * range, otherwise only print the initial bit and rescan. - */ - for (i=0; i < cmd->o.arg1; i++) - if (map[i/32] & (1<<(i & 31))) { - for (j=i+1; j < cmd->o.arg1; j++) - if (!(map[ j/32] & (1<<(j & 31)))) - break; - printf("%c%d", comma, i+x); - if (j>i+2) { /* range has at least 3 elements */ - printf("-%d", j-1+x); - i = j-1; - } - comma = ','; - } - printf("}"); - return; - } - /* - * len == 2 indicates a single IP, whereas lists of 1 or more - * addr/mask pairs have len = (2n+1). We convert len to n so we - * use that to count the number of entries. - */ - for (len = len / 2; len > 0; len--, a += 2) { - int mb = /* mask length */ - (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? - 32 : contigmask((uint8_t *)&(a[1]), 32); - if (mb == 32 && do_resolv) - he = gethostbyaddr((char *)&(a[0]), sizeof(in_addr_t), AF_INET); - if (he != NULL) /* resolved to name */ - printf("%s", he->h_name); - else if (mb == 0) /* any */ - printf("any"); - else { /* numeric IP followed by some kind of mask */ - printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) ); - if (mb < 0) - printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) ); - else if (mb < 32) - printf("/%d", mb); - } - if (len > 1) - printf(","); - } -} - -/* - * prints a MAC address/mask pair - */ -static void -print_mac(uint8_t *addr, uint8_t *mask) -{ - int l = contigmask(mask, 48); - - if (l == 0) - printf(" any"); - else { - printf(" %02x:%02x:%02x:%02x:%02x:%02x", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); - if (l == -1) - printf("&%02x:%02x:%02x:%02x:%02x:%02x", - mask[0], mask[1], mask[2], - mask[3], mask[4], mask[5]); - else if (l < 48) - printf("/%d", l); - } -} - -static void -fill_icmptypes(ipfw_insn_u32 *cmd, char *av) -{ - uint8_t type; - - cmd->d[0] = 0; - while (*av) { - if (*av == ',') - av++; - - type = strtoul(av, &av, 0); - - if (*av != ',' && *av != '\0') - errx(EX_DATAERR, "invalid ICMP type"); - - if (type > 31) - errx(EX_DATAERR, "ICMP type out of range"); - - cmd->d[0] |= 1 << type; - } - cmd->o.opcode = O_ICMPTYPE; - cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); -} - -static void -print_icmptypes(ipfw_insn_u32 *cmd) -{ - int i; - char sep= ' '; - - printf(" icmptypes"); - for (i = 0; i < 32; i++) { - if ( (cmd->d[0] & (1 << (i))) == 0) - continue; - printf("%c%d", sep, i); - sep = ','; - } -} - -/* - * show_ipfw() prints the body of an ipfw rule. - * Because the standard rule has at least proto src_ip dst_ip, we use - * a helper function to produce these entries if not provided explicitly. - * The first argument is the list of fields we have, the second is - * the list of fields we want to be printed. - * - * Special cases if we have provided a MAC header: - * + if the rule does not contain IP addresses/ports, do not print them; - * + if the rule does not contain an IP proto, print "all" instead of "ip"; - * - * Once we have 'have_options', IP header fields are printed as options. - */ -#define HAVE_PROTO 0x0001 -#define HAVE_SRCIP 0x0002 -#define HAVE_DSTIP 0x0004 -#define HAVE_MAC 0x0008 -#define HAVE_MACTYPE 0x0010 -#define HAVE_OPTIONS 0x8000 - -#define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) -static void -show_prerequisites(int *flags, int want, int cmd) -{ - if ( (*flags & HAVE_IP) == HAVE_IP) - *flags |= HAVE_OPTIONS; - - if ( (*flags & (HAVE_MAC|HAVE_MACTYPE|HAVE_OPTIONS)) == HAVE_MAC && - cmd != O_MAC_TYPE) { - /* - * mac-type was optimized out by the compiler, - * restore it - */ - printf(" any"); - *flags |= HAVE_MACTYPE | HAVE_OPTIONS; - return; - } - if ( !(*flags & HAVE_OPTIONS)) { - if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) - printf(" ip"); - if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) - printf(" from any"); - if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) - printf(" to any"); - } - *flags |= want; -} - -static void -show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) -{ - static int twidth = 0; - int l; - ipfw_insn *cmd; - char *comment = NULL; /* ptr to comment if we have one */ - int proto = 0; /* default */ - int flags = 0; /* prerequisites */ - ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ - int or_block = 0; /* we are in an or block */ - uint32_t set_disable; - - bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); - - if (set_disable & (1 << rule->set)) { /* disabled */ - if (!show_sets) - return; - else - printf("# DISABLED "); - } - printf("%05u ", rule->rulenum); - - if (pcwidth>0 || bcwidth>0) - printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), - bcwidth, align_uint64(&rule->bcnt)); - - if (do_time == 2) - printf("%10u ", rule->timestamp); - else if (do_time == 1) { - char timestr[30]; - time_t t = (time_t)0; - - if (twidth == 0) { - strlcpy(timestr, ctime(&t), sizeof(timestr)); - *strchr(timestr, '\n') = '\0'; - twidth = strlen(timestr); - } - if (rule->timestamp) { -#if _FreeBSD_version < 500000 /* XXX check */ -#define _long_to_time(x) (time_t)(x) -#endif - t = _long_to_time(rule->timestamp); - - strlcpy(timestr, ctime(&t), sizeof(timestr)); - *strchr(timestr, '\n') = '\0'; - printf("%s ", timestr); - } else { - printf("%*s", twidth, " "); - } - } - - if (show_sets) - printf("set %d ", rule->set); - - /* - * print the optional "match probability" - */ - if (rule->cmd_len > 0) { - cmd = rule->cmd ; - if (cmd->opcode == O_PROB) { - ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; - double d = 1.0 * p->d[0]; - - d = (d / 0x7fffffff); - printf("prob %f ", d); - } - } - - /* - * first print actions - */ - for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); - l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { - switch(cmd->opcode) { - case O_CHECK_STATE: - printf("check-state"); - flags = HAVE_IP; /* avoid printing anything else */ - break; - - case O_ACCEPT: - printf("allow"); - break; - - case O_COUNT: - printf("count"); - break; - - case O_DENY: - printf("deny"); - break; - - case O_REJECT: - if (cmd->arg1 == ICMP_REJECT_RST) - printf("reset"); - else if (cmd->arg1 == ICMP_UNREACH_HOST) - printf("reject"); - else - print_reject_code(cmd->arg1); - break; - - case O_SKIPTO: - printf("skipto %u", cmd->arg1); - break; - - case O_PIPE: - printf("pipe %u", cmd->arg1); - break; - - case O_QUEUE: - printf("queue %u", cmd->arg1); - break; - - case O_DIVERT: - printf("divert %u", cmd->arg1); - break; - - case O_TEE: - printf("tee %u", cmd->arg1); - break; - - case O_FORWARD_IP: - { - ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; - - printf("fwd %s", inet_ntoa(s->sa.sin_addr)); - if (s->sa.sin_port) - printf(",%d", s->sa.sin_port); - } - break; - - case O_LOG: /* O_LOG is printed last */ - logptr = (ipfw_insn_log *)cmd; - break; - - default: - printf("** unrecognized action %d len %d", - cmd->opcode, cmd->len); - } - } - if (logptr) { - if (logptr->max_log > 0) - printf(" log logamount %d", logptr->max_log); - else - printf(" log"); - } - - /* - * then print the body. - */ - if (rule->_pad & 1) { /* empty rules before options */ - if (!do_compact) - printf(" ip from any to any"); - flags |= HAVE_IP | HAVE_OPTIONS; - } - - for (l = rule->act_ofs, cmd = rule->cmd ; - l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { - /* useful alias */ - ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; - - show_prerequisites(&flags, 0, cmd->opcode); - - switch(cmd->opcode) { - case O_PROB: - break; /* done already */ - - case O_PROBE_STATE: - break; /* no need to print anything here */ - - case O_MACADDR2: { - ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; - - if ((cmd->len & F_OR) && !or_block) - printf(" {"); - if (cmd->len & F_NOT) - printf(" not"); - printf(" MAC"); - flags |= HAVE_MAC; - print_mac(m->addr, m->mask); - print_mac(m->addr + 6, m->mask + 6); - } - break; - - case O_MAC_TYPE: - if ((cmd->len & F_OR) && !or_block) - printf(" {"); - print_newports((ipfw_insn_u16 *)cmd, IPPROTO_ETHERTYPE, - (flags & HAVE_OPTIONS) ? cmd->opcode : 0); - flags |= HAVE_MAC | HAVE_MACTYPE | HAVE_OPTIONS; - break; - - case O_IP_SRC: - case O_IP_SRC_MASK: - case O_IP_SRC_ME: - case O_IP_SRC_SET: - show_prerequisites(&flags, HAVE_PROTO, 0); - if (!(flags & HAVE_SRCIP)) - printf(" from"); - if ((cmd->len & F_OR) && !or_block) - printf(" {"); - print_ip((ipfw_insn_ip *)cmd, - (flags & HAVE_OPTIONS) ? " src-ip" : ""); - flags |= HAVE_SRCIP; - break; - - case O_IP_DST: - case O_IP_DST_MASK: - case O_IP_DST_ME: - case O_IP_DST_SET: - show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); - if (!(flags & HAVE_DSTIP)) - printf(" to"); - if ((cmd->len & F_OR) && !or_block) - printf(" {"); - print_ip((ipfw_insn_ip *)cmd, - (flags & HAVE_OPTIONS) ? " dst-ip" : ""); - flags |= HAVE_DSTIP; - break; - - case O_IP_DSTPORT: - show_prerequisites(&flags, HAVE_IP, 0); - case O_IP_SRCPORT: - show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); - if ((cmd->len & F_OR) && !or_block) - printf(" {"); - print_newports((ipfw_insn_u16 *)cmd, proto, - (flags & HAVE_OPTIONS) ? cmd->opcode : 0); - break; - - case O_PROTO: { - struct protoent *pe; - - if ((cmd->len & F_OR) && !or_block) - printf(" {"); - if (cmd->len & F_NOT) - printf(" not"); - proto = cmd->arg1; - pe = getprotobynumber(cmd->arg1); - if (flags & HAVE_OPTIONS) - printf(" proto"); - if (pe) - printf(" %s", pe->p_name); - else - printf(" %u", cmd->arg1); - } - flags |= HAVE_PROTO; - break; - - default: /*options ... */ - show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); - if ((cmd->len & F_OR) && !or_block) - printf(" {"); - if (cmd->len & F_NOT && cmd->opcode != O_IN) - printf(" not"); - switch(cmd->opcode) { - case O_FRAG: - printf(" frag"); - break; - - case O_IN: - printf(cmd->len & F_NOT ? " out" : " in"); - break; - - case O_LAYER2: - printf(" layer2"); - break; - case O_XMIT: - case O_RECV: - case O_VIA: { - char const *s; - ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; - - if (cmd->opcode == O_XMIT) - s = "xmit"; - else if (cmd->opcode == O_RECV) - s = "recv"; - else /* if (cmd->opcode == O_VIA) */ - s = "via"; - if (cmdif->name[0] == '\0') - printf(" %s %s", s, - inet_ntoa(cmdif->p.ip)); - else if (cmdif->p.unit == -1) - printf(" %s %s*", s, cmdif->name); - else - printf(" %s %s%d", s, cmdif->name, - cmdif->p.unit); - } - break; - - case O_IPID: - if (F_LEN(cmd) == 1) - printf(" ipid %u", cmd->arg1 ); - else - print_newports((ipfw_insn_u16 *)cmd, 0, - O_IPID); - break; - - case O_IPTTL: - if (F_LEN(cmd) == 1) - printf(" ipttl %u", cmd->arg1 ); - else - print_newports((ipfw_insn_u16 *)cmd, 0, - O_IPTTL); - break; - - case O_IPVER: - printf(" ipver %u", cmd->arg1 ); - break; - - case O_IPPRECEDENCE: - printf(" ipprecedence %u", (cmd->arg1) >> 5 ); - break; - - case O_IPLEN: - if (F_LEN(cmd) == 1) - printf(" iplen %u", cmd->arg1 ); - else - print_newports((ipfw_insn_u16 *)cmd, 0, - O_IPLEN); - break; - - case O_IPOPT: - print_flags("ipoptions", cmd, f_ipopts); - break; - - case O_IPTOS: - print_flags("iptos", cmd, f_iptos); - break; - - case O_ICMPTYPE: - print_icmptypes((ipfw_insn_u32 *)cmd); - break; - - case O_ESTAB: - printf(" established"); - break; - - case O_TCPFLAGS: - print_flags("tcpflags", cmd, f_tcpflags); - break; - - case O_TCPOPTS: - print_flags("tcpoptions", cmd, f_tcpopts); - break; - - case O_TCPWIN: - printf(" tcpwin %d", ntohs(cmd->arg1)); - break; - - case O_TCPACK: - printf(" tcpack %d", ntohl(cmd32->d[0])); - break; - - case O_TCPSEQ: - printf(" tcpseq %d", ntohl(cmd32->d[0])); - break; - - case O_UID: - { - struct passwd *pwd = getpwuid(cmd32->d[0]); - - if (pwd) - printf(" uid %s", pwd->pw_name); - else - printf(" uid %u", cmd32->d[0]); - } - break; - - case O_GID: - { - struct group *grp = getgrgid(cmd32->d[0]); - - if (grp) - printf(" gid %s", grp->gr_name); - else - printf(" gid %u", cmd32->d[0]); - } - break; - - case O_VERREVPATH: - printf(" verrevpath"); - break; - - case O_IPSEC: - printf(" ipsec"); - break; - - case O_NOP: - comment = (char *)(cmd + 1); - break; - - case O_KEEP_STATE: - printf(" keep-state"); - break; - - case O_LIMIT: - { - struct _s_x *p = limit_masks; - ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; - uint8_t x = c->limit_mask; - char const *comma = " "; - - printf(" limit"); - for (; p->x != 0 ; p++) - if ((x & p->x) == p->x) { - x &= ~p->x; - printf("%s%s", comma, p->s); - comma = ","; - } - printf(" %d", c->conn_limit); - } - break; - - default: - printf(" [opcode %d len %d]", - cmd->opcode, cmd->len); - } - } - if (cmd->len & F_OR) { - printf(" or"); - or_block = 1; - } else if (or_block) { - printf(" }"); - or_block = 0; - } - } - show_prerequisites(&flags, HAVE_IP, 0); - if (comment) - printf(" // %s", comment); - printf("\n"); -} - -static void -show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) -{ - struct protoent *pe; - struct in_addr a; - uint16_t rulenum; - - if (!do_expired) { - if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) - return; - } - bcopy(&d->rule, &rulenum, sizeof(rulenum)); - printf("%05d", rulenum); - if (pcwidth>0 || bcwidth>0) - printf(" %*llu %*llu (%ds)", pcwidth, - align_uint64(&d->pcnt), bcwidth, - align_uint64(&d->bcnt), d->expire); - switch (d->dyn_type) { - case O_LIMIT_PARENT: - printf(" PARENT %d", d->count); - break; - case O_LIMIT: - printf(" LIMIT"); - break; - case O_KEEP_STATE: /* bidir, no mask */ - printf(" STATE"); - break; - } - - if ((pe = getprotobynumber(d->id.proto)) != NULL) - printf(" %s", pe->p_name); - else - printf(" proto %u", d->id.proto); - - a.s_addr = htonl(d->id.src_ip); - printf(" %s %d", inet_ntoa(a), d->id.src_port); - - a.s_addr = htonl(d->id.dst_ip); - printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); - printf("\n"); -} - -static int -sort_q(const void *pa, const void *pb) -{ - int rev = (do_sort < 0); - int field = rev ? -do_sort : do_sort; - long long res = 0; - const struct dn_flow_queue *a = pa; - const struct dn_flow_queue *b = pb; - - switch (field) { - case 1: /* pkts */ - res = a->len - b->len; - break; - case 2: /* bytes */ - res = a->len_bytes - b->len_bytes; - break; - - case 3: /* tot pkts */ - res = a->tot_pkts - b->tot_pkts; - break; - - case 4: /* tot bytes */ - res = a->tot_bytes - b->tot_bytes; - break; - } - if (res < 0) - res = -1; - if (res > 0) - res = 1; - return (int)(rev ? res : -res); -} - -static void -list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) -{ - int l; - - printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", - fs->flow_mask.proto, - fs->flow_mask.src_ip, fs->flow_mask.src_port, - fs->flow_mask.dst_ip, fs->flow_mask.dst_port); - if (fs->rq_elements == 0) - return; - - printf("BKT Prot ___Source IP/port____ " - "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); - if (do_sort != 0) - heapsort(q, fs->rq_elements, sizeof *q, sort_q); - for (l = 0; l < fs->rq_elements; l++) { - struct in_addr ina; - struct protoent *pe; - - ina.s_addr = htonl(q[l].id.src_ip); - printf("%3d ", q[l].hash_slot); - pe = getprotobynumber(q[l].id.proto); - if (pe) - printf("%-4s ", pe->p_name); - else - printf("%4u ", q[l].id.proto); - printf("%15s/%-5d ", - inet_ntoa(ina), q[l].id.src_port); - ina.s_addr = htonl(q[l].id.dst_ip); - printf("%15s/%-5d ", - inet_ntoa(ina), q[l].id.dst_port); - printf("%4qu %8qu %2u %4u %3u\n", - q[l].tot_pkts, q[l].tot_bytes, - q[l].len, q[l].len_bytes, q[l].drops); - if (verbose) - printf(" S %20qd F %20qd\n", - q[l].S, q[l].F); - } -} - -static void -print_flowset_parms(struct dn_flow_set *fs, char *prefix) -{ - int l; - char qs[30]; - char plr[30]; - char red[90]; /* Display RED parameters */ - - l = fs->qsize; - if (fs->flags_fs & DN_QSIZE_IS_BYTES) { - if (l >= 8192) - snprintf(qs, sizeof(qs), "%d KB", l / 1024); - else - snprintf(qs, sizeof(qs), "%d B", l); - } else - snprintf(qs, sizeof(qs), "%3d sl.", l); - if (fs->plr) - snprintf(plr, sizeof(plr), "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); - else - plr[0] = '\0'; - if (fs->flags_fs & DN_IS_RED) /* RED parameters */ - snprintf(red, sizeof(red), - "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", - (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', - 1.0 * fs->w_q / (double)(1 << SCALE_RED), - SCALE_VAL(fs->min_th), - SCALE_VAL(fs->max_th), - 1.0 * fs->max_p / (double)(1 << SCALE_RED)); - else - snprintf(red, sizeof(red), "droptail"); - - printf("%s %s%s %d queues (%d buckets) %s\n", - prefix, qs, plr, fs->rq_elements, fs->rq_size, red); -} - -static void -list_pipes(void *data, uint nbytes, int ac, char *av[]) -{ - int rulenum; - void *next = data; - struct dn_pipe *p = (struct dn_pipe *) data; - struct dn_flow_set *fs; - struct dn_flow_queue *q; - int l; - - if (ac > 0) - rulenum = strtoul(*av++, NULL, 10); - else - rulenum = 0; - for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) { - double b = p->bandwidth; - char buf[30]; - char prefix[80]; - - if (p->next.sle_next != (struct dn_pipe *)DN_IS_PIPE) - break; /* done with pipes, now queues */ - - /* - * compute length, as pipe have variable size - */ - l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); - next = (char *)p + l; - nbytes -= l; - - if (rulenum != 0 && rulenum != p->pipe_nr) - continue; - - /* - * Print rate (or clocking interface) - */ - if (p->if_name[0] != '\0') - snprintf(buf, sizeof(buf), "%s", p->if_name); - else if (b == 0) - snprintf(buf, sizeof(buf), "unlimited"); - else if (b >= 1000000) - snprintf(buf, sizeof(buf), "%7.3f Mbit/s", b/1000000); - else if (b >= 1000) - snprintf(buf, sizeof(buf), "%7.3f Kbit/s", b/1000); - else - snprintf(buf, sizeof(buf), "%7.3f bit/s ", b); - - snprintf(prefix, sizeof(prefix), "%05d: %s %4d ms ", - p->pipe_nr, buf, p->delay); - print_flowset_parms(&(p->fs), prefix); - if (verbose) - printf(" V %20qd\n", p->V >> MY_M); - - q = (struct dn_flow_queue *)(p+1); - list_queues(&(p->fs), q); - } - for (fs = next; nbytes >= sizeof *fs; fs = next) { - char prefix[80]; - - if (fs->next.sle_next != (struct dn_flow_set *)DN_IS_QUEUE) - break; - l = sizeof(*fs) + fs->rq_elements * sizeof(*q); - next = (char *)fs + l; - nbytes -= l; - q = (struct dn_flow_queue *)(fs+1); - snprintf(prefix, sizeof(prefix), "q%05d: weight %d pipe %d ", - fs->fs_nr, fs->weight, fs->parent_nr); - print_flowset_parms(fs, prefix); - list_queues(fs, q); - } -} - -/* - * This one handles all set-related commands - * ipfw set { show | enable | disable } - * ipfw set swap X Y - * ipfw set move X to Y - * ipfw set move rule X to Y - */ -static void -sets_handler(int ac, char *av[]) -{ - uint32_t set_disable, masks[2]; - int i, nbytes; - uint16_t rulenum; - uint8_t cmd, new_set; - - ac--; - av++; - - if (!ac) - errx(EX_USAGE, "set needs command"); - if (!strncmp(*av, "show", strlen(*av)) ) { - void *data; - char const *msg; - - nbytes = sizeof(struct ip_fw); - if ((data = calloc(1, nbytes)) == NULL) - err(EX_OSERR, "calloc"); - - if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0) - err(EX_OSERR, "getsockopt(IP_FW_GET)"); - bcopy(&((struct ip_fw *)data)->next_rule, - &set_disable, sizeof(set_disable)); - - for (i = 0, msg = "disable" ; i < RESVD_SET; i++) - if ((set_disable & (1< RESVD_SET) - errx(EX_DATAERR, "invalid set number %s", av[0]); - if (!isdigit(*(av[1])) || new_set > RESVD_SET) - errx(EX_DATAERR, "invalid set number %s", av[1]); - masks[0] = (4 << 24) | (new_set << 16) | (rulenum); - - bzero(&rule, sizeof(rule)); - rule.set_masks[0] = masks[0]; - - i = do_cmd(IP_FW_DEL, &rule, sizeof(rule)); - } else if (!strncmp(*av, "move", strlen(*av))) { - struct ip_fw rule; - ac--; av++; - if (ac && !strncmp(*av, "rule", strlen(*av))) { - cmd = 2; - ac--; av++; - } else - cmd = 3; - if (ac != 3 || strncmp(av[1], "to", strlen(*av))) - errx(EX_USAGE, "syntax: set move [rule] X to Y"); - rulenum = atoi(av[0]); - new_set = atoi(av[2]); - if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) || - (cmd == 2 && rulenum == 65535) ) - errx(EX_DATAERR, "invalid source number %s", av[0]); - if (!isdigit(*(av[2])) || new_set > RESVD_SET) - errx(EX_DATAERR, "invalid dest. set %s", av[1]); - masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); - - bzero(&rule, sizeof(rule)); - rule.set_masks[0] = masks[0]; - - i = do_cmd(IP_FW_DEL, &rule, sizeof(rule)); - } else if (!strncmp(*av, "disable", strlen(*av)) || - !strncmp(*av, "enable", strlen(*av)) ) { - int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0; - struct ip_fw rule; - - ac--; av++; - masks[0] = masks[1] = 0; - - while (ac) { - if (isdigit(**av)) { - i = atoi(*av); - if (i < 0 || i > RESVD_SET) - errx(EX_DATAERR, - "invalid set number %d", i); - masks[which] |= (1<= nalloc) { - nalloc = nalloc * 2 + 200; - nbytes = nalloc; - if ((data = realloc(data, nbytes)) == NULL) - err(EX_OSERR, "realloc"); - - if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0) - err(EX_OSERR, "getsockopt(IP_%s_GET)", - do_pipe ? "DUMMYNET" : "FW"); - } - - if (do_pipe) { - list_pipes(data, nbytes, ac, av); - goto done; - } - - /* - * Count static rules. They have variable size so we - * need to scan the list to count them. - */ - for (nstat = 1, r = data, lim = (char *)data + nbytes; - r->rulenum < 65535 && (char *)r < lim; - ++nstat, r = NEXT(r) ) - ; /* nothing */ - - /* - * Count dynamic rules. This is easier as they have - * fixed size. - */ - r = NEXT(r); - dynrules = (ipfw_dyn_rule *)r ; - n = (char *)r - (char *)data; - ndyn = (nbytes - n) / sizeof *dynrules; - - /* if showing stats, figure out column widths ahead of time */ - bcwidth = pcwidth = 0; - if (show_counters) { - for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { - /* packet counter */ - width = snprintf(NULL, 0, "%llu", - align_uint64(&r->pcnt)); - if (width > pcwidth) - pcwidth = width; - - /* byte counter */ - width = snprintf(NULL, 0, "%llu", - align_uint64(&r->bcnt)); - if (width > bcwidth) - bcwidth = width; - } - } - if (do_dynamic && ndyn) { - for (n = 0, d = dynrules; n < ndyn; n++, d++) { - width = snprintf(NULL, 0, "%llu", - align_uint64(&d->pcnt)); - if (width > pcwidth) - pcwidth = width; - - width = snprintf(NULL, 0, "%llu", - align_uint64(&d->bcnt)); - if (width > bcwidth) - bcwidth = width; - } - } - /* if no rule numbers were specified, list all rules */ - if (ac == 0) { - for (n = 0, r = data; n < nstat; n++, r = NEXT(r) ) - show_ipfw(r, pcwidth, bcwidth); - - if (do_dynamic && ndyn) { - printf("## Dynamic rules (%d):\n", ndyn); - for (n = 0, d = dynrules; n < ndyn; n++, d++) - show_dyn_ipfw(d, pcwidth, bcwidth); - } - goto done; - } - - /* display specific rules requested on command line */ - - for (lac = ac, lav = av; lac != 0; lac--) { - /* convert command line rule # */ - last = rnum = strtoul(*lav++, &endptr, 10); - if (*endptr == '-') - last = strtoul(endptr+1, &endptr, 10); - if (*endptr) { - exitval = EX_USAGE; - warnx("invalid rule number: %s", *(lav - 1)); - continue; - } - for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) { - if (r->rulenum > last) - break; - if (r->rulenum >= rnum && r->rulenum <= last) { - show_ipfw(r, pcwidth, bcwidth); - seen = 1; - } - } - if (!seen) { - /* give precedence to other error(s) */ - if (exitval == EX_OK) - exitval = EX_UNAVAILABLE; - warnx("rule %lu does not exist", rnum); - } - } - - if (do_dynamic && ndyn) { - printf("## Dynamic rules:\n"); - for (lac = ac, lav = av; lac != 0; lac--) { - rnum = strtoul(*lav++, &endptr, 10); - if (*endptr == '-') - last = strtoul(endptr+1, &endptr, 10); - if (*endptr) - /* already warned */ - continue; - for (n = 0, d = dynrules; n < ndyn; n++, d++) { - uint16_t rulenum; - - bcopy(&d->rule, &rulenum, sizeof(rulenum)); - if (rulenum > rnum) - break; - if (r->rulenum >= rnum && r->rulenum <= last) - show_dyn_ipfw(d, pcwidth, bcwidth); - } - } - } - - ac = 0; - -done: - free(data); - - if (exitval != EX_OK) - exit(exitval); -#undef NEXT -} - -static void -show_usage(void) -{ - fprintf(stderr, "usage: ipfw [options]\n" -"do \"ipfw -h\" or see ipfw manpage for details\n" -); - exit(EX_USAGE); -} - -static void -help(void) -{ - fprintf(stderr, -"ipfw syntax summary (but please do read the ipfw(8) manpage):\n" -"ipfw [-acdeftTnNpqS] where is one of:\n" -"add [num] [set N] [prob x] RULE-BODY\n" -"{pipe|queue} N config PIPE-BODY\n" -"[pipe|queue] {zero|delete|show} [N{,N}]\n" -"set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" -"\n" -"RULE-BODY: check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n" -"ACTION: check-state | allow | count | deny | reject | skipto N |\n" -" {divert|tee} PORT | forward ADDR | pipe N | queue N\n" -"ADDR: [ MAC dst src ether_type ] \n" -" [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" -"IPADDR: [not] { any | me | ip/bits{x,y,z} | IPLIST }\n" -"IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" -"OPTION_LIST: OPTION [OPTION_LIST]\n" -"OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n" -" estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" -" iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" -" ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" -" mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" -" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" -" verrevpath\n" -); -exit(0); -} - - -static int -lookup_host (char *host, struct in_addr *ipaddr) -{ - struct hostent *he; - - if (!inet_aton(host, ipaddr)) { - if ((he = gethostbyname(host)) == NULL) - return(-1); - *ipaddr = *(struct in_addr *)he->h_addr_list[0]; - } - return(0); -} - -/* - * fills the addr and mask fields in the instruction as appropriate from av. - * Update length as appropriate. - * The following formats are allowed: - * any matches any IP. Actually returns an empty instruction. - * me returns O_IP_*_ME - * 1.2.3.4 single IP address - * 1.2.3.4:5.6.7.8 address:mask - * 1.2.3.4/24 address/mask - * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet - * We can have multiple comma-separated address/mask entries. - */ -static void -fill_ip(ipfw_insn_ip *cmd, char *av) -{ - int len = 0; - uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; - - cmd->o.len &= ~F_LEN_MASK; /* zero len */ - - if (!strncmp(av, "any", strlen(av))) - return; - - if (!strncmp(av, "me", strlen(av))) { - cmd->o.len |= F_INSN_SIZE(ipfw_insn); - return; - } - - while (av) { - /* - * After the address we can have '/' or ':' indicating a mask, - * ',' indicating another address follows, '{' indicating a - * set of addresses of unspecified size. - */ - char *p = strpbrk(av, "/:,{"); - int masklen; - char md; - - if (p) { - md = *p; - *p++ = '\0'; - } else - md = '\0'; - - if (lookup_host(av, (struct in_addr *)&d[0]) != 0) - errx(EX_NOHOST, "hostname ``%s'' unknown", av); - switch (md) { - case ':': - if (!inet_aton(p, (struct in_addr *)&d[1])) - errx(EX_DATAERR, "bad netmask ``%s''", p); - break; - case '/': - masklen = atoi(p); - if (masklen == 0) - d[1] = htonl(0); /* mask */ - else if (masklen > 32) - errx(EX_DATAERR, "bad width ``%s''", p); - else - d[1] = htonl(~0 << (32 - masklen)); - break; - case '{': /* no mask, assume /24 and put back the '{' */ - d[1] = htonl(~0 << (32 - 24)); - *(--p) = md; - break; - - case ',': /* single address plus continuation */ - *(--p) = md; - /* FALLTHROUGH */ - case 0: /* initialization value */ - default: - d[1] = htonl(~0); /* force /32 */ - break; - } - d[0] &= d[1]; /* mask base address with mask */ - /* find next separator */ - if (p) - p = strpbrk(p, ",{"); - if (p && *p == '{') { - /* - * We have a set of addresses. They are stored as follows: - * arg1 is the set size (powers of 2, 2..256) - * addr is the base address IN HOST FORMAT - * mask.. is an array of arg1 bits (rounded up to - * the next multiple of 32) with bits set - * for each host in the map. - */ - uint32_t *map = (uint32_t *)&cmd->mask; - int low, high; - int i = contigmask((uint8_t *)&(d[1]), 32); - - if (len > 0) - errx(EX_DATAERR, "address set cannot be in a list"); - if (i < 24 || i > 31) - errx(EX_DATAERR, "invalid set with mask %d", i); - cmd->o.arg1 = 1<<(32-i); /* map length */ - d[0] = ntohl(d[0]); /* base addr in host format */ - cmd->o.opcode = O_IP_DST_SET; /* default */ - cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; - for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) - map[i] = 0; /* clear map */ - - av = p + 1; - low = d[0] & 0xff; - high = low + cmd->o.arg1 - 1; - /* - * Here, i stores the previous value when we specify a range - * of addresses within a mask, e.g. 45-63. i = -1 means we - * have no previous value. - */ - i = -1; /* previous value in a range */ - while (isdigit(*av)) { - char *s; - int a = strtol(av, &s, 0); - - if (s == av) { /* no parameter */ - if (*av != '}') - errx(EX_DATAERR, "set not closed"); - if (i != -1) - errx(EX_DATAERR, "incomplete range %d-", i); - break; - } - if (a < low || a > high) - errx(EX_DATAERR, "addr %d out of range [%d-%d]", - a, low, high); - a -= low; - if (i == -1) /* no previous in range */ - i = a; - else { /* check that range is valid */ - if (i > a) - errx(EX_DATAERR, "invalid range %d-%d", - i+low, a+low); - if (*s == '-') - errx(EX_DATAERR, "double '-' in range"); - } - for (; i <= a; i++) - map[i/32] |= 1<<(i & 31); - i = -1; - if (*s == '-') - i = a; - else if (*s == '}') - break; - av = s+1; - } - return; - } - av = p; - if (av) /* then *av must be a ',' */ - av++; - - /* Check this entry */ - if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ - /* - * 'any' turns the entire list into a NOP. - * 'not any' never matches, so it is removed from the - * list unless it is the only item, in which case we - * report an error. - */ - if (cmd->o.len & F_NOT) { /* "not any" never matches */ - if (av == NULL && len == 0) /* only this entry */ - errx(EX_DATAERR, "not any never matches"); - } - /* else do nothing and return */ - return; - } - /* A single IP can be stored in an optimized format */ - if (d[1] == IP_MASK_ALL && av == NULL && len == 0) { - cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); - return; - } - len += 2; /* two words... */ - d += 2; - } /* end while */ - cmd->o.len |= len+1; -} - - -/* - * helper function to process a set of flags and set bits in the - * appropriate masks. - */ -static void -fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, - struct _s_x *flags, char *p) -{ - uint8_t set=0, clear=0; - - while (p && *p) { - char *q; /* points to the separator */ - int val; - uint8_t *which; /* mask we are working on */ - - if (*p == '!') { - p++; - which = &clear; - } else - which = &set; - q = strchr(p, ','); - if (q) - *q++ = '\0'; - val = match_token(flags, p); - if (val <= 0) - errx(EX_DATAERR, "invalid flag %s", p); - *which |= (uint8_t)val; - p = q; - } - cmd->opcode = opcode; - cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; - cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); -} - - -static void -delete(int ac, char *av[]) -{ - struct ip_fw rule; - struct dn_pipe p; - int i; - int exitval = EX_OK; - int do_set = 0; - - memset(&p, 0, sizeof p); - - av++; ac--; - if (ac > 0 && !strncmp(*av, "set", strlen(*av))) { - do_set = 1; /* delete set */ - ac--; av++; - } - - /* Rule number */ - while (ac && isdigit(**av)) { - i = atoi(*av); av++; ac--; - if (do_pipe) { - if (do_pipe == 1) - p.pipe_nr = i; - else - p.fs.fs_nr = i; - i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p); - if (i) { - exitval = 1; - warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", - do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr); - } - } else { - bzero(&rule, sizeof(rule)); - if (do_set) { - rule.set_masks[0] = (i & 0xffff) | (do_set << 24); - } - else { - rule.rulenum = i; - } - i = do_cmd(IP_FW_DEL, &rule, sizeof(rule)); - if (i) { - exitval = EX_UNAVAILABLE; - warn("rule %u: setsockopt(IP_FW_DEL)", - rule.rulenum); - } - } - } - if (exitval != EX_OK) - exit(exitval); -} - - -/* - * fill the interface structure. We do not check the name as we can - * create interfaces dynamically, so checking them at insert time - * makes relatively little sense. - * A '*' following the name means any unit. - */ -static void -fill_iface(ipfw_insn_if *cmd, char *arg) -{ - cmd->name[0] = '\0'; - cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); - - /* Parse the interface or address */ - if (!strcmp(arg, "any")) - cmd->o.len = 0; /* effectively ignore this command */ - else if (!isdigit(*arg)) { - char *q; - - strncpy(cmd->name, arg, sizeof(cmd->name)); - cmd->name[sizeof(cmd->name) - 1] = '\0'; - /* find first digit or wildcard */ - for (q = cmd->name; *q && !isdigit(*q) && *q != '*'; q++) - continue; - cmd->p.unit = (*q == '*') ? -1 : atoi(q); - *q = '\0'; - } else if (!inet_aton(arg, &cmd->p.ip)) - errx(EX_DATAERR, "bad ip address ``%s''", arg); -} - -/* - * the following macro returns an error message if we run out of - * arguments. - */ -#define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} - -static void -config_pipe(int ac, char **av) -{ - struct dn_pipe p; - int i; - char *end; - uint32_t a; - void *par = NULL; - - memset(&p, 0, sizeof p); - - av++; ac--; - /* Pipe number */ - if (ac && isdigit(**av)) { - i = atoi(*av); av++; ac--; - if (do_pipe == 1) - p.pipe_nr = i; - else - p.fs.fs_nr = i; - } - while (ac > 0) { - double d; - int tok = match_token(dummynet_params, *av); - ac--; av++; - - switch(tok) { - case TOK_NOERROR: - p.fs.flags_fs |= DN_NOERROR; - break; - - case TOK_PLR: - NEED1("plr needs argument 0..1\n"); - d = strtod(av[0], NULL); - if (d > 1) - d = 1; - else if (d < 0) - d = 0; - p.fs.plr = (int)(d*0x7fffffff); - ac--; av++; - break; - - case TOK_QUEUE: - NEED1("queue needs queue size\n"); - end = NULL; - p.fs.qsize = strtoul(av[0], &end, 0); - if (*end == 'K' || *end == 'k') { - p.fs.flags_fs |= DN_QSIZE_IS_BYTES; - p.fs.qsize *= 1024; - } else if (*end == 'B' || !strncmp(end, "by", 2)) { - p.fs.flags_fs |= DN_QSIZE_IS_BYTES; - } - ac--; av++; - break; - - case TOK_BUCKETS: - NEED1("buckets needs argument\n"); - p.fs.rq_size = strtoul(av[0], NULL, 0); - ac--; av++; - break; - - case TOK_MASK: - NEED1("mask needs mask specifier\n"); - /* - * per-flow queue, mask is dst_ip, dst_port, - * src_ip, src_port, proto measured in bits - */ - par = NULL; - - p.fs.flow_mask.dst_ip = 0; - p.fs.flow_mask.src_ip = 0; - p.fs.flow_mask.dst_port = 0; - p.fs.flow_mask.src_port = 0; - p.fs.flow_mask.proto = 0; - end = NULL; - - while (ac >= 1) { - uint32_t *p32 = NULL; - uint16_t *p16 = NULL; - - tok = match_token(dummynet_params, *av); - ac--; av++; - switch(tok) { - case TOK_ALL: - /* - * special case, all bits significant - */ - p.fs.flow_mask.dst_ip = ~0; - p.fs.flow_mask.src_ip = ~0; - p.fs.flow_mask.dst_port = ~0; - p.fs.flow_mask.src_port = ~0; - p.fs.flow_mask.proto = ~0; - p.fs.flags_fs |= DN_HAVE_FLOW_MASK; - goto end_mask; - - case TOK_DSTIP: - p32 = &p.fs.flow_mask.dst_ip; - break; - - case TOK_SRCIP: - p32 = &p.fs.flow_mask.src_ip; - break; - - case TOK_DSTPORT: - p16 = &p.fs.flow_mask.dst_port; - break; - - case TOK_SRCPORT: - p16 = &p.fs.flow_mask.src_port; - break; - - case TOK_PROTO: - break; - - default: - ac++; av--; /* backtrack */ - goto end_mask; - } - if (ac < 1) - errx(EX_USAGE, "mask: value missing"); - if (*av[0] == '/') { - a = strtoul(av[0]+1, &end, 0); - a = (a == 32) ? ~0 : (1 << a) - 1; - } else - a = strtoul(av[0], &end, 0); - if (p32 != NULL) - *p32 = a; - else if (p16 != NULL) { - if (a > 65535) - errx(EX_DATAERR, - "mask: must be 16 bit"); - *p16 = (uint16_t)a; - } else { - if (a > 255) - errx(EX_DATAERR, - "mask: must be 8 bit"); - p.fs.flow_mask.proto = (uint8_t)a; - } - if (a != 0) - p.fs.flags_fs |= DN_HAVE_FLOW_MASK; - ac--; av++; - } /* end while, config masks */ -end_mask: - break; - - case TOK_RED: - case TOK_GRED: - NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); - p.fs.flags_fs |= DN_IS_RED; - if (tok == TOK_GRED) - p.fs.flags_fs |= DN_IS_GENTLE_RED; - /* - * the format for parameters is w_q/min_th/max_th/max_p - */ - if ((end = strsep(&av[0], "/"))) { - double w_q = strtod(end, NULL); - if (w_q > 1 || w_q <= 0) - errx(EX_DATAERR, "0 < w_q <= 1"); - p.fs.w_q = (int) (w_q * (1 << SCALE_RED)); - } - if ((end = strsep(&av[0], "/"))) { - p.fs.min_th = strtoul(end, &end, 0); - if (*end == 'K' || *end == 'k') - p.fs.min_th *= 1024; - } - if ((end = strsep(&av[0], "/"))) { - p.fs.max_th = strtoul(end, &end, 0); - if (*end == 'K' || *end == 'k') - p.fs.max_th *= 1024; - } - if ((end = strsep(&av[0], "/"))) { - double max_p = strtod(end, NULL); - if (max_p > 1 || max_p <= 0) - errx(EX_DATAERR, "0 < max_p <= 1"); - p.fs.max_p = (int)(max_p * (1 << SCALE_RED)); - } - ac--; av++; - break; - - case TOK_DROPTAIL: - p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); - break; - - case TOK_BW: - NEED1("bw needs bandwidth or interface\n"); - if (do_pipe != 1) - errx(EX_DATAERR, "bandwidth only valid for pipes"); - /* - * set clocking interface or bandwidth value - */ - if (av[0][0] >= 'a' && av[0][0] <= 'z') { - int l = sizeof(p.if_name)-1; - /* interface name */ - strncpy(p.if_name, av[0], l); - p.if_name[l] = '\0'; - p.bandwidth = 0; - } else { - p.if_name[0] = '\0'; - p.bandwidth = strtoul(av[0], &end, 0); - if (*end == 'K' || *end == 'k') { - end++; - p.bandwidth *= 1000; - } else if (*end == 'M') { - end++; - p.bandwidth *= 1000000; - } - if (*end == 'B' || !strncmp(end, "by", 2)) - p.bandwidth *= 8; - if (p.bandwidth < 0) - errx(EX_DATAERR, "bandwidth too large"); - } - ac--; av++; - break; - - case TOK_DELAY: - if (do_pipe != 1) - errx(EX_DATAERR, "delay only valid for pipes"); - NEED1("delay needs argument 0..10000ms\n"); - p.delay = strtoul(av[0], NULL, 0); - ac--; av++; - break; - - case TOK_WEIGHT: - if (do_pipe == 1) - errx(EX_DATAERR,"weight only valid for queues"); - NEED1("weight needs argument 0..100\n"); - p.fs.weight = strtoul(av[0], &end, 0); - ac--; av++; - break; - - case TOK_PIPE: - if (do_pipe == 1) - errx(EX_DATAERR,"pipe only valid for queues"); - NEED1("pipe needs pipe_number\n"); - p.fs.parent_nr = strtoul(av[0], &end, 0); - ac--; av++; - break; - - default: - errx(EX_DATAERR, "unrecognised option ``%s''", *(--av)); - } - } - if (do_pipe == 1) { - if (p.pipe_nr == 0) - errx(EX_DATAERR, "pipe_nr must be > 0"); - if (p.delay > 10000) - errx(EX_DATAERR, "delay must be < 10000"); - } else { /* do_pipe == 2, queue */ - if (p.fs.parent_nr == 0) - errx(EX_DATAERR, "pipe must be > 0"); - if (p.fs.weight >100) - errx(EX_DATAERR, "weight must be <= 100"); - } - if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) { - if (p.fs.qsize > 1024*1024) - errx(EX_DATAERR, "queue size must be < 1MB"); - } else { - if (p.fs.qsize > 100) - errx(EX_DATAERR, "2 <= queue size <= 100"); - } - if (p.fs.flags_fs & DN_IS_RED) { - size_t len; - int lookup_depth, avg_pkt_size; - double s, idle, weight, w_q; - struct clockinfo ck; - int t; - - if (p.fs.min_th >= p.fs.max_th) - errx(EX_DATAERR, "min_th %d must be < than max_th %d", - p.fs.min_th, p.fs.max_th); - if (p.fs.max_th == 0) - errx(EX_DATAERR, "max_th must be > 0"); - - len = sizeof(int); - if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", - &lookup_depth, &len, NULL, 0) == -1) - - errx(1, "sysctlbyname(\"%s\")", - "net.inet.ip.dummynet.red_lookup_depth"); - if (lookup_depth == 0) - errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" - " must be greater than zero"); - - len = sizeof(int); - if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", - &avg_pkt_size, &len, NULL, 0) == -1) - - errx(1, "sysctlbyname(\"%s\")", - "net.inet.ip.dummynet.red_avg_pkt_size"); - if (avg_pkt_size == 0) - errx(EX_DATAERR, - "net.inet.ip.dummynet.red_avg_pkt_size must" - " be greater than zero"); - - len = sizeof(struct clockinfo); - if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1) - errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); - - /* - * Ticks needed for sending a medium-sized packet. - * Unfortunately, when we are configuring a WF2Q+ queue, we - * do not have bandwidth information, because that is stored - * in the parent pipe, and also we have multiple queues - * competing for it. So we set s=0, which is not very - * correct. But on the other hand, why do we want RED with - * WF2Q+ ? - */ - if (p.bandwidth==0) /* this is a WF2Q+ queue */ - s = 0; - else - s = ck.hz * avg_pkt_size * 8 / p.bandwidth; - - /* - * max idle time (in ticks) before avg queue size becomes 0. - * NOTA: (3/w_q) is approx the value x so that - * (1-w_q)^x < 10^-3. - */ - w_q = ((double)p.fs.w_q) / (1 << SCALE_RED); - idle = s * 3. / w_q; - p.fs.lookup_step = (int)idle / lookup_depth; - if (!p.fs.lookup_step) - p.fs.lookup_step = 1; - weight = 1 - w_q; - for (t = p.fs.lookup_step; t > 0; --t) - weight *= weight; - p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); - } - i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p); - if (i) - err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); -} - -static void -get_mac_addr_mask(char *p, uint8_t *addr, uint8_t *mask) -{ - int i, l; - - for (i=0; i<6; i++) - addr[i] = mask[i] = 0; - if (!strcmp(p, "any")) - return; - - for (i=0; *p && i<6;i++, p++) { - addr[i] = strtol(p, &p, 16); - if (*p != ':') /* we start with the mask */ - break; - } - if (*p == '/') { /* mask len */ - l = strtol(p+1, &p, 0); - for (i=0; l>0; l -=8, i++) - mask[i] = (l >=8) ? 0xff : (~0) << (8-l); - } else if (*p == '&') { /* mask */ - for (i=0, p++; *p && i<6;i++, p++) { - mask[i] = strtol(p, &p, 16); - if (*p != ':') - break; - } - } else if (*p == '\0') { - for (i=0; i<6; i++) - mask[i] = 0xff; - } - for (i=0; i<6; i++) - addr[i] &= mask[i]; -} - -/* - * helper function, updates the pointer to cmd with the length - * of the current command, and also cleans up the first word of - * the new command in case it has been clobbered before. - */ -static ipfw_insn * -next_cmd(ipfw_insn *cmd) -{ - cmd += F_LEN(cmd); - bzero(cmd, sizeof(*cmd)); - return cmd; -} - -/* - * Takes arguments and copies them into a comment - */ -static void -fill_comment(ipfw_insn *cmd, int ac, char **av) -{ - int i, l; - char *p = (char *)(cmd + 1); - - cmd->opcode = O_NOP; - cmd->len = (cmd->len & (F_NOT | F_OR)); - - /* Compute length of comment string. */ - for (i = 0, l = 0; i < ac; i++) - l += strlen(av[i]) + 1; - if (l == 0) - return; - if (l > 84) - errx(EX_DATAERR, - "comment too long (max 80 chars)"); - l = 1 + (l+3)/4; - cmd->len = (cmd->len & (F_NOT | F_OR)) | l; - for (i = 0; i < ac; i++) { - /* length being checked above (max 80 chars) */ - strlcpy(p, av[i], 80); - p += strlen(av[i]); - *p++ = ' '; - } - *(--p) = '\0'; -} - -/* - * A function to fill simple commands of size 1. - * Existing flags are preserved. - */ -static void -fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) -{ - cmd->opcode = opcode; - cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; - cmd->arg1 = arg; -} - -/* - * Fetch and add the MAC address and type, with masks. This generates one or - * two microinstructions, and returns the pointer to the last one. - */ -static ipfw_insn * -add_mac(ipfw_insn *cmd, int ac, char *av[]) -{ - ipfw_insn_mac *mac; - - if (ac < 2) - errx(EX_DATAERR, "MAC dst src"); - - cmd->opcode = O_MACADDR2; - cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); - - mac = (ipfw_insn_mac *)cmd; - get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ - get_mac_addr_mask(av[1], &(mac->addr[6]), &(mac->mask[6])); /* src */ - return cmd; -} - -static ipfw_insn * -add_mactype(ipfw_insn *cmd, int ac, char *av) -{ - if (ac < 1) - errx(EX_DATAERR, "missing MAC type"); - if (strcmp(av, "any") != 0) { /* we have a non-null type */ - fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); - cmd->opcode = O_MAC_TYPE; - return cmd; - } else - return NULL; -} - -static ipfw_insn * -add_proto(ipfw_insn *cmd, char *av) -{ - struct protoent *pe; - u_char proto = 0; - - if (!strncmp(av, "all", strlen(av))) - ; /* same as "ip" */ - else if ((proto = atoi(av)) > 0) - ; /* all done! */ - else if ((pe = getprotobyname(av)) != NULL) - proto = pe->p_proto; - else - return NULL; - if (proto != IPPROTO_IP) - fill_cmd(cmd, O_PROTO, 0, proto); - return cmd; -} - -static ipfw_insn * -add_srcip(ipfw_insn *cmd, char *av) -{ - fill_ip((ipfw_insn_ip *)cmd, av); - if (cmd->opcode == O_IP_DST_SET) /* set */ - cmd->opcode = O_IP_SRC_SET; - else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ - cmd->opcode = O_IP_SRC_ME; - else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ - cmd->opcode = O_IP_SRC; - else /* addr/mask */ - cmd->opcode = O_IP_SRC_MASK; - return cmd; -} - -static ipfw_insn * -add_dstip(ipfw_insn *cmd, char *av) -{ - fill_ip((ipfw_insn_ip *)cmd, av); - if (cmd->opcode == O_IP_DST_SET) /* set */ - ; - else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ - cmd->opcode = O_IP_DST_ME; - else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ - cmd->opcode = O_IP_DST; - else /* addr/mask */ - cmd->opcode = O_IP_DST_MASK; - return cmd; -} - -static ipfw_insn * -add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) -{ - if (!strncmp(av, "any", strlen(av))) { - return NULL; - } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { - /* XXX todo: check that we have a protocol with ports */ - cmd->opcode = opcode; - return cmd; - } - return NULL; -} - -/* - * Parse arguments and assemble the microinstructions which make up a rule. - * Rules are added into the 'rulebuf' and then copied in the correct order - * into the actual rule. - * - * The syntax for a rule starts with the action, followed by an - * optional log action, and the various match patterns. - * In the assembled microcode, the first opcode must be an O_PROBE_STATE - * (generated if the rule includes a keep-state option), then the - * various match patterns, the "log" action, and the actual action. - * - */ -static void -add(int ac, char *av[]) -{ - /* - * rules are added into the 'rulebuf' and then copied in - * the correct order into the actual rule. - * Some things that need to go out of order (prob, action etc.) - * go into actbuf[]. - */ - static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; - - ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; - ipfw_insn *first_cmd; /* first match pattern */ - - struct ip_fw *rule; - - /* - * various flags used to record that we entered some fields. - */ - ipfw_insn *have_state = NULL; /* check-state or keep-state */ - - int i; - - int open_par = 0; /* open parenthesis ( */ - - /* proto is here because it is used to fetch ports */ - u_char proto = IPPROTO_IP; /* default protocol */ - - double match_prob = 1; /* match probability, default is always match */ - - bzero(actbuf, sizeof(actbuf)); /* actions go here */ - bzero(cmdbuf, sizeof(cmdbuf)); - bzero(rulebuf, sizeof(rulebuf)); - - rule = (struct ip_fw *)rulebuf; - cmd = (ipfw_insn *)cmdbuf; - action = (ipfw_insn *)actbuf; - - av++; ac--; - - /* [rule N] -- Rule number optional */ - if (ac && isdigit(**av)) { - rule->rulenum = atoi(*av); - av++; - ac--; - } - - /* [set N] -- set number (0..RESVD_SET), optional */ - if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { - int set = strtoul(av[1], NULL, 10); - if (set < 0 || set > RESVD_SET) - errx(EX_DATAERR, "illegal set %s", av[1]); - rule->set = set; - av += 2; ac -= 2; - } - - /* [prob D] -- match probability, optional */ - if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) { - match_prob = strtod(av[1], NULL); - - if (match_prob <= 0 || match_prob > 1) - errx(EX_DATAERR, "illegal match prob. %s", av[1]); - av += 2; ac -= 2; - } - - /* action -- mandatory */ - NEED1("missing action"); - i = match_token(rule_actions, *av); - ac--; av++; - action->len = 1; /* default */ - switch(i) { - case TOK_CHECKSTATE: - have_state = action; - action->opcode = O_CHECK_STATE; - break; - - case TOK_ACCEPT: - action->opcode = O_ACCEPT; - break; - - case TOK_DENY: - action->opcode = O_DENY; - action->arg1 = 0; - break; - - case TOK_REJECT: - action->opcode = O_REJECT; - action->arg1 = ICMP_UNREACH_HOST; - break; - - case TOK_RESET: - action->opcode = O_REJECT; - action->arg1 = ICMP_REJECT_RST; - break; - - case TOK_UNREACH: - action->opcode = O_REJECT; - NEED1("missing reject code"); - fill_reject_code(&action->arg1, *av); - ac--; av++; - break; - - case TOK_COUNT: - action->opcode = O_COUNT; - break; - - case TOK_QUEUE: - case TOK_PIPE: - action->len = F_INSN_SIZE(ipfw_insn_pipe); - case TOK_SKIPTO: - if (i == TOK_QUEUE) - action->opcode = O_QUEUE; - else if (i == TOK_PIPE) - action->opcode = O_PIPE; - else if (i == TOK_SKIPTO) - action->opcode = O_SKIPTO; - NEED1("missing skipto/pipe/queue number"); - action->arg1 = strtoul(*av, NULL, 10); - av++; ac--; - break; - - case TOK_DIVERT: - case TOK_TEE: - action->opcode = (i == TOK_DIVERT) ? O_DIVERT : O_TEE; - NEED1("missing divert/tee port"); - action->arg1 = strtoul(*av, NULL, 0); - if (action->arg1 == 0) { - struct servent *s; - setservent(1); - s = getservbyname(av[0], "divert"); - if (s != NULL) - action->arg1 = ntohs(s->s_port); - else - errx(EX_DATAERR, "illegal divert/tee port"); - } - ac--; av++; - break; - - case TOK_FORWARD: { - ipfw_insn_sa *p = (ipfw_insn_sa *)action; - char *s, *end; - - NEED1("missing forward address[:port]"); - - action->opcode = O_FORWARD_IP; - action->len = F_INSN_SIZE(ipfw_insn_sa); - - p->sa.sin_len = sizeof(struct sockaddr_in); - p->sa.sin_family = AF_INET; - p->sa.sin_port = 0; - /* - * locate the address-port separator (':' or ',') - */ - s = strchr(*av, ':'); - if (s == NULL) - s = strchr(*av, ','); - if (s != NULL) { - *(s++) = '\0'; - i = strtoport(s, &end, 0 /* base */, 0 /* proto */); - if (s == end) - errx(EX_DATAERR, - "illegal forwarding port ``%s''", s); - p->sa.sin_port = (u_short)i; - } - lookup_host(*av, &(p->sa.sin_addr)); - } - ac--; av++; - break; - - case TOK_COMMENT: - /* pretend it is a 'count' rule followed by the comment */ - action->opcode = O_COUNT; - ac++; av--; /* go back... */ - break; - - default: - errx(EX_DATAERR, "invalid action %s", av[-1]); - } - action = next_cmd(action); - - /* - * [log [logamount N]] -- log, optional - * - * If exists, it goes first in the cmdbuf, but then it is - * skipped in the copy section to the end of the buffer. - */ - if (ac && !strncmp(*av, "log", strlen(*av))) { - ipfw_insn_log *c = (ipfw_insn_log *)cmd; - int l; - - cmd->len = F_INSN_SIZE(ipfw_insn_log); - cmd->opcode = O_LOG; - av++; ac--; - if (ac && !strncmp(*av, "logamount", strlen(*av))) { - ac--; av++; - NEED1("logamount requires argument"); - l = atoi(*av); - if (l < 0) - errx(EX_DATAERR, "logamount must be positive"); - c->max_log = l; - ac--; av++; - } - cmd = next_cmd(cmd); - } - - if (have_state) /* must be a check-state, we are done */ - goto done; - -#define OR_START(target) \ - if (ac && (*av[0] == '(' || *av[0] == '{')) { \ - if (open_par) \ - errx(EX_USAGE, "nested \"(\" not allowed"); \ - prev = NULL; \ - open_par = 1; \ - if ( (av[0])[1] == '\0') { \ - ac--; av++; \ - } else \ - (*av)++; \ - } \ - target: \ - - -#define CLOSE_PAR \ - if (open_par) { \ - if (ac && ( \ - !strncmp(*av, ")", strlen(*av)) || \ - !strncmp(*av, "}", strlen(*av)) )) { \ - prev = NULL; \ - open_par = 0; \ - ac--; av++; \ - } else \ - errx(EX_USAGE, "missing \")\""); \ - } - -#define NOT_BLOCK \ - if (ac && !strncmp(*av, "not", strlen(*av))) { \ - if (cmd->len & F_NOT) \ - errx(EX_USAGE, "double \"not\" not allowed"); \ - cmd->len |= F_NOT; \ - ac--; av++; \ - } - -#define OR_BLOCK(target) \ - if (ac && !strncmp(*av, "or", strlen(*av))) { \ - if (prev == NULL || open_par == 0) \ - errx(EX_DATAERR, "invalid OR block"); \ - prev->len |= F_OR; \ - ac--; av++; \ - goto target; \ - } \ - CLOSE_PAR; - - first_cmd = cmd; - -#if 0 - /* - * MAC addresses, optional. - * If we have this, we skip the part "proto from src to dst" - * and jump straight to the option parsing. - */ - NOT_BLOCK; - NEED1("missing protocol"); - if (!strncmp(*av, "MAC", strlen(*av)) || - !strncmp(*av, "mac", strlen(*av))) { - ac--; av++; /* the "MAC" keyword */ - add_mac(cmd, ac, av); /* exits in case of errors */ - cmd = next_cmd(cmd); - ac -= 2; av += 2; /* dst-mac and src-mac */ - NOT_BLOCK; - NEED1("missing mac type"); - if (add_mactype(cmd, ac, av[0])) - cmd = next_cmd(cmd); - ac--; av++; /* any or mac-type */ - goto read_options; - } -#endif - - /* - * protocol, mandatory - */ - OR_START(get_proto); - NOT_BLOCK; - NEED1("missing protocol"); - if (add_proto(cmd, *av)) { - av++; ac--; - if (F_LEN(cmd) == 0) /* plain IP */ - proto = 0; - else { - proto = cmd->arg1; - prev = cmd; - cmd = next_cmd(cmd); - } - } else if (first_cmd != cmd) { - errx(EX_DATAERR, "invalid protocol ``%s''", *av); - } else - goto read_options; - OR_BLOCK(get_proto); - - /* - * "from", mandatory - */ - if (!ac || strncmp(*av, "from", strlen(*av))) - errx(EX_USAGE, "missing ``from''"); - ac--; av++; - - /* - * source IP, mandatory - */ - OR_START(source_ip); - NOT_BLOCK; /* optional "not" */ - NEED1("missing source address"); - if (add_srcip(cmd, *av)) { - ac--; av++; - if (F_LEN(cmd) != 0) { /* ! any */ - prev = cmd; - cmd = next_cmd(cmd); - } - } - OR_BLOCK(source_ip); - - /* - * source ports, optional - */ - NOT_BLOCK; /* optional "not" */ - if (ac) { - if (!strncmp(*av, "any", strlen(*av)) || - add_ports(cmd, *av, proto, O_IP_SRCPORT)) { - ac--; av++; - if (F_LEN(cmd) != 0) - cmd = next_cmd(cmd); - } - } - - /* - * "to", mandatory - */ - if (!ac || strncmp(*av, "to", strlen(*av))) - errx(EX_USAGE, "missing ``to''"); - av++; ac--; - - /* - * destination, mandatory - */ - OR_START(dest_ip); - NOT_BLOCK; /* optional "not" */ - NEED1("missing dst address"); - if (add_dstip(cmd, *av)) { - ac--; av++; - if (F_LEN(cmd) != 0) { /* ! any */ - prev = cmd; - cmd = next_cmd(cmd); - } - } - OR_BLOCK(dest_ip); - - /* - * dest. ports, optional - */ - NOT_BLOCK; /* optional "not" */ - if (ac) { - if (!strncmp(*av, "any", strlen(*av)) || - add_ports(cmd, *av, proto, O_IP_DSTPORT)) { - ac--; av++; - if (F_LEN(cmd) != 0) - cmd = next_cmd(cmd); - } - } - -read_options: - if (ac && first_cmd == cmd) { - /* - * nothing specified so far, store in the rule to ease - * printout later. - */ - rule->_pad = 1; - } - prev = NULL; - while (ac) { - char *s; - ipfw_insn_u32 *cmd32; /* alias for cmd */ - - s = *av; - cmd32 = (ipfw_insn_u32 *)cmd; - - if (*s == '!') { /* alternate syntax for NOT */ - if (cmd->len & F_NOT) - errx(EX_USAGE, "double \"not\" not allowed"); - cmd->len = F_NOT; - s++; - } - i = match_token(rule_options, s); - ac--; av++; - switch(i) { - case TOK_NOT: - if (cmd->len & F_NOT) - errx(EX_USAGE, "double \"not\" not allowed"); - cmd->len = F_NOT; - break; - - case TOK_OR: - if (open_par == 0 || prev == NULL) - errx(EX_USAGE, "invalid \"or\" block"); - prev->len |= F_OR; - break; - - case TOK_STARTBRACE: - if (open_par) - errx(EX_USAGE, "+nested \"(\" not allowed"); - open_par = 1; - break; - - case TOK_ENDBRACE: - if (!open_par) - errx(EX_USAGE, "+missing \")\""); - open_par = 0; - prev = NULL; - break; - - case TOK_IN: - fill_cmd(cmd, O_IN, 0, 0); - break; - - case TOK_OUT: - cmd->len ^= F_NOT; /* toggle F_NOT */ - fill_cmd(cmd, O_IN, 0, 0); - break; - - case TOK_FRAG: - fill_cmd(cmd, O_FRAG, 0, 0); - break; - - case TOK_LAYER2: - fill_cmd(cmd, O_LAYER2, 0, 0); - break; - - case TOK_XMIT: - case TOK_RECV: - case TOK_VIA: - NEED1("recv, xmit, via require interface name" - " or address"); - fill_iface((ipfw_insn_if *)cmd, av[0]); - ac--; av++; - if (F_LEN(cmd) == 0) /* not a valid address */ - break; - if (i == TOK_XMIT) - cmd->opcode = O_XMIT; - else if (i == TOK_RECV) - cmd->opcode = O_RECV; - else if (i == TOK_VIA) - cmd->opcode = O_VIA; - break; - - case TOK_ICMPTYPES: - NEED1("icmptypes requires list of types"); - fill_icmptypes((ipfw_insn_u32 *)cmd, *av); - av++; ac--; - break; - - case TOK_IPTTL: - NEED1("ipttl requires TTL"); - if (strpbrk(*av, "-,")) { - if (!add_ports(cmd, *av, 0, O_IPTTL)) - errx(EX_DATAERR, "invalid ipttl %s", *av); - } else - fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); - ac--; av++; - break; - - case TOK_IPID: - NEED1("ipid requires id"); - if (strpbrk(*av, "-,")) { - if (!add_ports(cmd, *av, 0, O_IPID)) - errx(EX_DATAERR, "invalid ipid %s", *av); - } else - fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); - ac--; av++; - break; - - case TOK_IPLEN: - NEED1("iplen requires length"); - if (strpbrk(*av, "-,")) { - if (!add_ports(cmd, *av, 0, O_IPLEN)) - errx(EX_DATAERR, "invalid ip len %s", *av); - } else - fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); - ac--; av++; - break; - - case TOK_IPVER: - NEED1("ipver requires version"); - fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); - ac--; av++; - break; - - case TOK_IPPRECEDENCE: - NEED1("ipprecedence requires value"); - fill_cmd(cmd, O_IPPRECEDENCE, 0, - (strtoul(*av, NULL, 0) & 7) << 5); - ac--; av++; - break; - - case TOK_IPOPTS: - NEED1("missing argument for ipoptions"); - fill_flags(cmd, O_IPOPT, f_ipopts, *av); - ac--; av++; - break; - - case TOK_IPTOS: - NEED1("missing argument for iptos"); - fill_flags(cmd, O_IPTOS, f_iptos, *av); - ac--; av++; - break; - - case TOK_UID: - NEED1("uid requires argument"); - { - char *end; - uid_t uid; - struct passwd *pwd; - - cmd->opcode = O_UID; - uid = strtoul(*av, &end, 0); - pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); - if (pwd == NULL) - errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); - cmd32->d[0] = pwd->pw_uid; - cmd->len = F_INSN_SIZE(ipfw_insn_u32); - ac--; av++; - } - break; - - case TOK_GID: - NEED1("gid requires argument"); - { - char *end; - gid_t gid; - struct group *grp; - - cmd->opcode = O_GID; - gid = strtoul(*av, &end, 0); - grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); - if (grp == NULL) - errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); - cmd32->d[0] = grp->gr_gid; - cmd->len = F_INSN_SIZE(ipfw_insn_u32); - ac--; av++; - } - break; - - case TOK_ESTAB: - fill_cmd(cmd, O_ESTAB, 0, 0); - break; - - case TOK_SETUP: - fill_cmd(cmd, O_TCPFLAGS, 0, - (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); - break; - - case TOK_TCPOPTS: - NEED1("missing argument for tcpoptions"); - fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); - ac--; av++; - break; - - case TOK_TCPSEQ: - case TOK_TCPACK: - NEED1("tcpseq/tcpack requires argument"); - cmd->len = F_INSN_SIZE(ipfw_insn_u32); - cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; - cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); - ac--; av++; - break; - - case TOK_TCPWIN: - NEED1("tcpwin requires length"); - fill_cmd(cmd, O_TCPWIN, 0, - htons(strtoul(*av, NULL, 0))); - ac--; av++; - break; - - case TOK_TCPFLAGS: - NEED1("missing argument for tcpflags"); - cmd->opcode = O_TCPFLAGS; - fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); - ac--; av++; - break; - - case TOK_KEEPSTATE: - if (open_par) - errx(EX_USAGE, "keep-state cannot be part " - "of an or block"); - if (have_state) - errx(EX_USAGE, "only one of keep-state " - "and limit is allowed"); - have_state = cmd; - fill_cmd(cmd, O_KEEP_STATE, 0, 0); - break; - - case TOK_LIMIT: - if (open_par) - errx(EX_USAGE, "limit cannot be part " - "of an or block"); - if (have_state) - errx(EX_USAGE, "only one of keep-state " - "and limit is allowed"); - NEED1("limit needs mask and # of connections"); - have_state = cmd; - { - ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; - - cmd->len = F_INSN_SIZE(ipfw_insn_limit); - cmd->opcode = O_LIMIT; - c->limit_mask = 0; - c->conn_limit = 0; - for (; ac >1 ;) { - int val; - - val = match_token(limit_masks, *av); - if (val <= 0) - break; - c->limit_mask |= val; - ac--; av++; - } - c->conn_limit = atoi(*av); - if (c->conn_limit == 0) - errx(EX_USAGE, "limit: limit must be >0"); - if (c->limit_mask == 0) - errx(EX_USAGE, "missing limit mask"); - ac--; av++; - } - break; - - case TOK_PROTO: - NEED1("missing protocol"); - if (add_proto(cmd, *av)) { - proto = cmd->arg1; - ac--; av++; - } else - errx(EX_DATAERR, "invalid protocol ``%s''", - *av); - break; - - case TOK_SRCIP: - NEED1("missing source IP"); - if (add_srcip(cmd, *av)) { - ac--; av++; - } - break; - - case TOK_DSTIP: - NEED1("missing destination IP"); - if (add_dstip(cmd, *av)) { - ac--; av++; - } - break; - - case TOK_SRCPORT: - NEED1("missing source port"); - if (!strncmp(*av, "any", strlen(*av)) || - add_ports(cmd, *av, proto, O_IP_SRCPORT)) { - ac--; av++; - } else - errx(EX_DATAERR, "invalid source port %s", *av); - break; - - case TOK_DSTPORT: - NEED1("missing destination port"); - if (!strncmp(*av, "any", strlen(*av)) || - add_ports(cmd, *av, proto, O_IP_DSTPORT)) { - ac--; av++; - } else - errx(EX_DATAERR, "invalid destination port %s", - *av); - break; - - case TOK_MAC: - if (ac < 2) - errx(EX_USAGE, "MAC dst-mac src-mac"); - if (add_mac(cmd, ac, av)) { - ac -= 2; av += 2; - } - break; - - case TOK_MACTYPE: - NEED1("missing mac type"); - if (!add_mactype(cmd, ac, *av)) - errx(EX_DATAERR, "invalid mac type %s", *av); - ac--; av++; - break; - - case TOK_VERREVPATH: - fill_cmd(cmd, O_VERREVPATH, 0, 0); - break; - - case TOK_IPSEC: - fill_cmd(cmd, O_IPSEC, 0, 0); - break; - - case TOK_COMMENT: - fill_comment(cmd, ac, av); - av += ac; - ac = 0; - break; - - default: - errx(EX_USAGE, "unrecognised option [%d] %s", i, s); - } - if (F_LEN(cmd) > 0) { /* prepare to advance */ - prev = cmd; - cmd = next_cmd(cmd); - } - } - -done: - /* - * Now copy stuff into the rule. - * If we have a keep-state option, the first instruction - * must be a PROBE_STATE (which is generated here). - * If we have a LOG option, it was stored as the first command, - * and now must be moved to the top of the action part. - */ - dst = (ipfw_insn *)rule->cmd; - - /* - * First thing to write into the command stream is the match probability. - */ - if (match_prob != 1) { /* 1 means always match */ - dst->opcode = O_PROB; - dst->len = 2; - *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); - dst += dst->len; - } - - /* - * generate O_PROBE_STATE if necessary - */ - if (have_state && have_state->opcode != O_CHECK_STATE) { - fill_cmd(dst, O_PROBE_STATE, 0, 0); - dst = next_cmd(dst); - } - /* - * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT - */ - for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { - i = F_LEN(src); - - switch (src->opcode) { - case O_LOG: - case O_KEEP_STATE: - case O_LIMIT: - break; - default: - bcopy(src, dst, i * sizeof(uint32_t)); - dst += i; - } - } - - /* - * put back the have_state command as last opcode - */ - if (have_state && have_state->opcode != O_CHECK_STATE) { - i = F_LEN(have_state); - bcopy(have_state, dst, i * sizeof(uint32_t)); - dst += i; - } - /* - * start action section - */ - rule->act_ofs = dst - rule->cmd; - - /* - * put back O_LOG if necessary - */ - src = (ipfw_insn *)cmdbuf; - if (src->opcode == O_LOG) { - i = F_LEN(src); - bcopy(src, dst, i * sizeof(uint32_t)); - dst += i; - } - /* - * copy all other actions - */ - for (src = (ipfw_insn *)actbuf; src != action; src += i) { - i = F_LEN(src); - bcopy(src, dst, i * sizeof(uint32_t)); - dst += i; - } - - rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); - i = (char *)dst - (char *)rule; - - if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1) - err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); - if (!do_quiet) - show_ipfw(rule, 0, 0); -} - -static void -zero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) -{ - struct ip_fw rule; - int rulenum; - int failed = EX_OK; - char const *name = optname == IP_FW_ZERO ? "ZERO" : "RESETLOG"; - - av++; ac--; - bzero(&rule, sizeof(rule)); - - if (!ac) { - /* clear all entries - send empty rule */ - if (do_cmd(optname, &rule, sizeof(rule)) < 0) - err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); - if (!do_quiet) - printf("%s.\n", optname == IP_FW_ZERO ? - "Accounting cleared":"Logging counts reset"); - - return; - } - - while (ac) { - /* Rule number */ - if (isdigit(**av)) { - rulenum = atoi(*av); - av++; - ac--; - rule.rulenum = rulenum; - if (do_cmd(optname, &rule, sizeof(rule))) { - warn("rule %u: setsockopt(IP_FW_%s)", - rulenum, name); - failed = EX_UNAVAILABLE; - } else if (!do_quiet) - printf("Entry %d %s.\n", rulenum, - optname == IP_FW_ZERO ? - "cleared" : "logging count reset"); - } else { - errx(EX_USAGE, "invalid rule number ``%s''", *av); - } - } - if (failed != EX_OK) - exit(failed); -} - -static void -flush(int force) -{ - int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; - struct ip_fw rule; - - if (!force && !do_quiet) { /* need to ask user */ - int c; - - printf("Are you sure? [yn] "); - fflush(stdout); - do { - c = toupper(getc(stdin)); - while (c != '\n' && getc(stdin) != '\n') - if (feof(stdin)) - return; /* and do not flush */ - } while (c != 'Y' && c != 'N'); - printf("\n"); - if (c == 'N') /* user said no */ - return; - } - - if (cmd == IP_FW_FLUSH) { - /* send empty rule */ - bzero(&rule, sizeof(rule)); - if (do_cmd(cmd, &rule, sizeof(rule)) < 0) - err(EX_UNAVAILABLE, "setsockopt(IP_FW_FLUSH)"); - } - else { - if (do_cmd(cmd, NULL, 0) < 0) - err(EX_UNAVAILABLE, "setsockopt(IP_DUMMYNET_FLUSH)"); - } - if (!do_quiet) - printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); -} - -/* - * Free a the (locally allocated) copy of command line arguments. - */ -static void -free_args(int ac, char **av) -{ - int i; - - for (i=0; i < ac; i++) - free(av[i]); - free(av); -} - -/* - * Called with the arguments (excluding program name). - * Returns 0 if successful, 1 if empty command, errx() in case of errors. - */ -static int -ipfw_main(int oldac, char **oldav) -{ - int ch, ac, save_ac; - char **av, **save_av; - int do_acct = 0; /* Show packet/byte count */ - int do_force = 0; /* Don't ask for confirmation */ - -#define WHITESP " \t\f\v\n\r" - if (oldac == 0) - return 1; - else if (oldac == 1) { - /* - * If we are called with a single string, try to split it into - * arguments for subsequent parsing. - * But first, remove spaces after a ',', by copying the string - * in-place. - */ - char *arg = oldav[0]; /* The string... */ - int l = strlen(arg); - int copy = 0; /* 1 if we need to copy, 0 otherwise */ - int i, j; - for (i = j = 0; i < l; i++) { - if (arg[i] == '#') /* comment marker */ - break; - if (copy) { - arg[j++] = arg[i]; - copy = !index("," WHITESP, arg[i]); - } else { - copy = !index(WHITESP, arg[i]); - if (copy) - arg[j++] = arg[i]; - } - } - if (!copy && j > 0) /* last char was a 'blank', remove it */ - j--; - l = j; /* the new argument length */ - arg[j++] = '\0'; - if (l == 0) /* empty string! */ - return 1; - - /* - * First, count number of arguments. Because of the previous - * processing, this is just the number of blanks plus 1. - */ - for (i = 0, ac = 1; i < l; i++) - if (index(WHITESP, arg[i]) != NULL) - ac++; - - av = calloc(ac, sizeof(char *)); - - /* - * Second, copy arguments from cmd[] to av[]. For each one, - * j is the initial character, i is the one past the end. - */ - for (ac = 0, i = j = 0; i < l; i++) - if (index(WHITESP, arg[i]) != NULL || i == l-1) { - if (i == l-1) - i++; - av[ac] = calloc(i-j+1, 1); - bcopy(arg+j, av[ac], i-j); - ac++; - j = i + 1; - } - } else { - /* - * If an argument ends with ',' join with the next one. - * Just add its length to 'l' and continue. When we have a string - * without a ',' ending, we'll have the combined length in 'l' - */ - int first, i, l; - - av = calloc(oldac, sizeof(char *)); - for (first = i = ac = 0, l = 0; i < oldac; i++) { - char *arg = oldav[i]; - int k = strlen(arg); - - l += k; - if (arg[k-1] != ',' || i == oldac-1) { - int buflen = l+1; - /* Time to copy. */ - av[ac] = calloc(l+1, 1); - for (l=0; first <= i; first++) { - strlcat(av[ac]+l, oldav[first], buflen-l); - l += strlen(oldav[first]); - } - ac++; - l = 0; - first = i+1; - } - } - } - - /* Set the force flag for non-interactive processes */ - do_force = !isatty(STDIN_FILENO); - - /* Save arguments for final freeing of memory. */ - save_ac = ac; - save_av = av; - - optind = optreset = 0; - while ((ch = getopt(ac, av, "acdefhnNqs:STtv")) != -1) - switch (ch) { - case 'a': - do_acct = 1; - break; - - case 'c': - do_compact = 1; - break; - - case 'd': - do_dynamic = 1; - break; - - case 'e': - do_expired = 1; - break; - - case 'f': - do_force = 1; - break; - - case 'h': /* help */ - free_args(save_ac, save_av); - help(); - break; /* NOTREACHED */ - - case 'n': - test_only = 1; - break; - - case 'N': - do_resolv = 1; - break; - - case 'q': - do_quiet = 1; - break; - - case 's': /* sort */ - do_sort = atoi(optarg); - break; - - case 'S': - show_sets = 1; - break; - - case 't': - do_time = 1; - break; - - case 'T': - do_time = 2; /* numeric timestamp */ - break; - - case 'v': /* verbose */ - verbose = 1; - break; - - default: - free_args(save_ac, save_av); - return 1; - } - - ac -= optind; - av += optind; - NEED1("bad arguments, for usage summary ``ipfw''"); - - /* - * An undocumented behaviour of ipfw1 was to allow rule numbers first, - * e.g. "100 add allow ..." instead of "add 100 allow ...". - * In case, swap first and second argument to get the normal form. - */ - if (ac > 1 && isdigit(*av[0])) { - char *p = av[0]; - - av[0] = av[1]; - av[1] = p; - } - - /* - * optional: pipe or queue - */ - do_pipe = 0; - if (!strncmp(*av, "pipe", strlen(*av))) - do_pipe = 1; - else if (!strncmp(*av, "queue", strlen(*av))) - do_pipe = 2; - if (do_pipe) { - ac--; - av++; - } - NEED1("missing command"); - - /* - * For pipes and queues we normally say 'pipe NN config' - * but the code is easier to parse as 'pipe config NN' - * so we swap the two arguments. - */ - if (do_pipe > 0 && ac > 1 && isdigit(*av[0])) { - char *p = av[0]; - - av[0] = av[1]; - av[1] = p; - } - - if (!strncmp(*av, "add", strlen(*av))) - add(ac, av); - else if (do_pipe && !strncmp(*av, "config", strlen(*av))) - config_pipe(ac, av); - else if (!strncmp(*av, "delete", strlen(*av))) - delete(ac, av); - else if (!strncmp(*av, "flush", strlen(*av))) - flush(do_force); - else if (!strncmp(*av, "zero", strlen(*av))) - zero(ac, av, IP_FW_ZERO); - else if (!strncmp(*av, "resetlog", strlen(*av))) - zero(ac, av, IP_FW_RESETLOG); - else if (!strncmp(*av, "print", strlen(*av)) || - !strncmp(*av, "list", strlen(*av))) - list(ac, av, do_acct); - else if (!strncmp(*av, "set", strlen(*av))) - sets_handler(ac, av); - else if (!strncmp(*av, "enable", strlen(*av))) - sysctl_handler(ac, av, 1); - else if (!strncmp(*av, "disable", strlen(*av))) - sysctl_handler(ac, av, 0); - else if (!strncmp(*av, "show", strlen(*av))) - list(ac, av, 1 /* show counters */); - else - errx(EX_USAGE, "bad command `%s'", *av); - - /* Free memory allocated in the argument parsing. */ - free_args(save_ac, save_av); - return 0; -} - - -static void -ipfw_readfile(int ac, char *av[]) -{ -#define MAX_ARGS 32 - char buf[BUFSIZ]; - char *cmd = NULL, *filename = av[ac-1]; - int c, lineno=0; - FILE *f = NULL; - pid_t preproc = 0; - - filename = av[ac-1]; - - while ((c = getopt(ac, av, "cNnp:qS")) != -1) { - switch(c) { - case 'c': - do_compact = 1; - break; - - case 'N': - do_resolv = 1; - break; - - case 'n': - test_only = 1; - break; - - case 'p': - cmd = optarg; - /* - * Skip previous args and delete last one, so we - * pass all but the last argument to the preprocessor - * via av[optind-1] - */ - av += optind - 1; - ac -= optind - 1; - av[ac-1] = NULL; - fprintf(stderr, "command is %s\n", av[0]); - break; - - case 'q': - do_quiet = 1; - break; - - case 'S': - show_sets = 1; - break; - - default: - errx(EX_USAGE, "bad arguments, for usage" - " summary ``ipfw''"); - } - - if (cmd != NULL) - break; - } - - if (cmd == NULL && ac != optind + 1) { - fprintf(stderr, "ac %d, optind %d\n", ac, optind); - errx(EX_USAGE, "extraneous filename arguments"); - } - - if ((f = fopen(filename, "r")) == NULL) - err(EX_UNAVAILABLE, "fopen: %s", filename); - - if (cmd != NULL) { /* pipe through preprocessor */ - int pipedes[2]; - - if (pipe(pipedes) == -1) - err(EX_OSERR, "cannot create pipe"); - - preproc = fork(); - if (preproc == -1) - err(EX_OSERR, "cannot fork"); - - if (preproc == 0) { - /* - * Child, will run the preprocessor with the - * file on stdin and the pipe on stdout. - */ - if (dup2(fileno(f), 0) == -1 - || dup2(pipedes[1], 1) == -1) - err(EX_OSERR, "dup2()"); - fclose(f); - close(pipedes[1]); - close(pipedes[0]); - execvp(cmd, av); - err(EX_OSERR, "execvp(%s) failed", cmd); - } else { /* parent, will reopen f as the pipe */ - fclose(f); - close(pipedes[1]); - if ((f = fdopen(pipedes[0], "r")) == NULL) { - int savederrno = errno; - - (void)kill(preproc, SIGTERM); - errno = savederrno; - err(EX_OSERR, "fdopen()"); - } - } - } - - while (fgets(buf, BUFSIZ, f)) { /* read commands */ - char linename[16]; - char *args[1]; - - lineno++; - snprintf(linename, sizeof(linename), "Line %d", lineno); - setprogname(linename); /* XXX */ - args[0] = buf; - ipfw_main(1, args); - } - fclose(f); - if (cmd != NULL) { - int status; - - if (waitpid(preproc, &status, 0) == -1) - errx(EX_OSERR, "waitpid()"); - if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) - errx(EX_UNAVAILABLE, - "preprocessor exited with status %d", - WEXITSTATUS(status)); - else if (WIFSIGNALED(status)) - errx(EX_UNAVAILABLE, - "preprocessor exited with signal %d", - WTERMSIG(status)); - } -} - -int -main(int ac, char *av[]) -{ - /* - * If the last argument is an absolute pathname, interpret it - * as a file to be preprocessed. - */ - - if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) - ipfw_readfile(ac, av); - else { - if (ipfw_main(ac-1, av+1)) - show_usage(); - } - return EX_OK; -} diff --git a/kdumpd.tproj/kdumpd.c b/kdumpd.tproj/kdumpd.c index 040def3..61762fe 100644 --- a/kdumpd.tproj/kdumpd.c +++ b/kdumpd.tproj/kdumpd.c @@ -63,6 +63,7 @@ __unused static const char copyright[] = #include "kdump.h" #include +#include #include #include #include @@ -80,6 +81,7 @@ __unused static const char copyright[] = #include "kdumpsubs.h" +#define DEFAULT_KDUMPD_PORTNO (1069) #define TIMEOUT 2 int peer; @@ -110,6 +112,7 @@ static struct dirlist { static int suppress_naks; static int logging = 1; static int ipchroot; +static int server_mode = 1; static char *errtomsg __P((int)); static void nak __P((int)); @@ -137,7 +140,7 @@ main(argc, argv) char *chuser = "nobody"; openlog("kdumpd", LOG_PID | LOG_NDELAY, LOG_FTP); - while ((ch = getopt(argc, argv, "cClns:u:")) != -1) { + while ((ch = getopt(argc, argv, "cClns:u:w")) != -1) { switch (ch) { case 'c': ipchroot = 1; @@ -157,6 +160,9 @@ main(argc, argv) case 'u': chuser = optarg; break; + case 'w': + server_mode = 0; + break; default: syslog(LOG_WARNING, "ignoring unknown option -%c", ch); } @@ -184,67 +190,70 @@ main(argc, argv) exit(1); } - on = 1; - if (ioctl(0, FIONBIO, &on) < 0) { - syslog(LOG_ERR, "ioctl(FIONBIO): %m"); - exit(1); - } - fromlen = sizeof (from); - n = recvfrom(0, buf, sizeof (buf), 0, - (struct sockaddr *)&from, &fromlen); - if (n < 0) { - syslog(LOG_ERR, "recvfrom: %m"); - exit(1); - } - /* - * Now that we have read the message out of the UDP - * socket, we fork and exit. Thus, inetd will go back - * to listening to the kdump port, and the next request - * to come in will start up a new instance of kdumpd. - * - * We do this so that inetd can run kdumpd in "wait" mode. - * The problem with kdumpd running in "nowait" mode is that - * inetd may get one or more successful "selects" on the - * kdump port before we do our receive, so more than one - * instance of kdumpd may be started up. Worse, if kdumpd - * breaks before doing the above "recvfrom", inetd would - * spawn endless instances, clogging the system. - */ - { - int pid; - int i; - socklen_t j; - - for (i = 1; i < 20; i++) { - pid = fork(); - if (pid < 0) { - sleep(i); - /* - * flush out to most recently sent request. - * - * This may drop some requests, but those - * will be resent by the clients when - * they timeout. The positive effect of - * this flush is to (try to) prevent more - * than one kdumpd being started up to service - * a single request from a single client. - */ - j = sizeof from; - i = recvfrom(0, buf, sizeof (buf), 0, - (struct sockaddr *)&from, &j); - if (i > 0) { - n = i; - fromlen = j; - } - } else { - break; - } + /* If we are not in server mode, skip the whole 'inetd' logic below. */ + if (server_mode) { + on = 1; + if (ioctl(0, FIONBIO, &on) < 0) { + syslog(LOG_ERR, "ioctl(FIONBIO): %m"); + exit(1); } - if (pid < 0) { - syslog(LOG_ERR, "fork: %m"); + fromlen = sizeof (from); + n = recvfrom(0, buf, sizeof (buf), 0, + (struct sockaddr *)&from, &fromlen); + if (n < 0) { + syslog(LOG_ERR, "recvfrom: %m"); exit(1); - } else if (pid != 0) { - exit(0); + } + /* + * Now that we have read the message out of the UDP + * socket, we fork and exit. Thus, inetd will go back + * to listening to the kdump port, and the next request + * to come in will start up a new instance of kdumpd. + * + * We do this so that inetd can run kdumpd in "wait" mode. + * The problem with kdumpd running in "nowait" mode is that + * inetd may get one or more successful "selects" on the + * kdump port before we do our receive, so more than one + * instance of kdumpd may be started up. Worse, if kdumpd + * breaks before doing the above "recvfrom", inetd would + * spawn endless instances, clogging the system. + */ + { + int pid; + int i; + socklen_t j; + + for (i = 1; i < 20; i++) { + pid = fork(); + if (pid < 0) { + sleep(i); + /* + * flush out to most recently sent request. + * + * This may drop some requests, but those + * will be resent by the clients when + * they timeout. The positive effect of + * this flush is to (try to) prevent more + * than one kdumpd being started up to service + * a single request from a single client. + */ + j = sizeof from; + i = recvfrom(0, buf, sizeof (buf), 0, + (struct sockaddr *)&from, &j); + if (i > 0) { + n = i; + fromlen = j; + } + } else { + break; + } + } + if (pid < 0) { + syslog(LOG_ERR, "fork: %m"); + exit(1); + } else if (pid != 0) { + exit(0); + } } } @@ -278,10 +287,9 @@ main(argc, argv) } chdir( "/" ); setuid(nobody->pw_uid); - } - else - if (0 != chdir(dirs->name)) + } else if (0 != chdir(dirs->name)) { syslog(LOG_ERR, "chdir%s: %m", dirs->name); + } from.sin_family = AF_INET; alarm(0); @@ -294,10 +302,32 @@ main(argc, argv) } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; + + if (!server_mode) { + sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_port = htons((uint16_t) DEFAULT_KDUMPD_PORTNO); + } + if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) { syslog(LOG_ERR, "bind: %m"); exit(1); } + + if (!server_mode) { + /* + * Wait for an incoming message from a remote peer, note that we need to + * populate n since kdump() expect the first message to be in buf + * already. + */ + socklen_t slen = sizeof(from); + n = recvfrom(peer, buf, sizeof(buf), 0, + (struct sockaddr *) &from, &slen); + if (n <= 0) { + syslog(LOG_ERR, "recvfrom: %m"); + exit(1); + } + } + if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) { syslog(LOG_ERR, "connect: %m"); exit(1); diff --git a/ndp.tproj/ndp.8 b/ndp.tproj/ndp.8 index a96e169..b1217eb 100644 --- a/ndp.tproj/ndp.8 +++ b/ndp.tproj/ndp.8 @@ -170,13 +170,16 @@ another device on the network is using the same link-local address. the interface is enabled to proxy neighbor discovery for global scope prefixes matching those on link at other interfaces. .It Xo -.Ic ignore_na -.Xc -ignore neighbor advertisements received on this interface. -.It Xo .Ic insecure do not use cryptographically generated addresses (CGA) on this interface. .Xc +.It Xo +.Ic replicated +Address autoconfiguration proceeds under the assumption that interface +configuration is replicated by a sleep proxy at another node on the link. +Disables optimistic DAD and sends unsolicited NA with O=1 when DAD completes. +Ignores DAD failures from other hardware addresses. +.Xc .El .It Fl l Show link-layer reachability information. diff --git a/ndp.tproj/ndp.c b/ndp.tproj/ndp.c index 2afce5d..01d64aa 100644 --- a/ndp.tproj/ndp.c +++ b/ndp.tproj/ndp.c @@ -1205,9 +1205,9 @@ ifinfo(int argc, char **argv) } while (0) SETFLAG("nud", ND6_IFF_PERFORMNUD); SETFLAG("proxy_prefixes", ND6_IFF_PROXY_PREFIXES); - SETFLAG("ignore_na", ND6_IFF_IGNORE_NA); SETFLAG("disabled", ND6_IFF_IFDISABLED); SETFLAG("insecure", ND6_IFF_INSECURE); + SETFLAG("replicated", ND6_IFF_REPLICATED); ND.flags = newflags; if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) { @@ -1248,17 +1248,19 @@ ifinfo(int argc, char **argv) } } if (ND.flags) { - printf("\nFlags: "); + printf("\nFlags: 0x%x ", ND.flags); if ((ND.flags & ND6_IFF_IFDISABLED) != 0) printf("IFDISABLED "); - if ((ND.flags & ND6_IFF_IGNORE_NA) != 0) - printf("IGNORE_NA "); if ((ND.flags & ND6_IFF_INSECURE) != 0) printf("INSECURE "); if ((ND.flags & ND6_IFF_PERFORMNUD) != 0) printf("PERFORMNUD "); if ((ND.flags & ND6_IFF_PROXY_PREFIXES) != 0) printf("PROXY_PREFIXES "); + if ((ND.flags & ND6_IFF_REPLICATED) != 0) + printf("REPLICATED "); + if ((ND.flags & ND6_IFF_DAD) != 0) + printf("DAD "); } putc('\n', stdout); #undef ND diff --git a/netstat.tproj/if.c b/netstat.tproj/if.c index 714e651..a0ef208 100644 --- a/netstat.tproj/if.c +++ b/netstat.tproj/if.c @@ -115,6 +115,7 @@ static char *qid2str(unsigned int); static char *qstate2str(unsigned int); static char *tcqslot2str(unsigned int); static char *rate2str(long double); +static char *pri2str(unsigned int i); #define AVGN_MAX 8 @@ -142,6 +143,8 @@ static void print_qfqstats(int slot, struct qfq_classstats *, struct queue_stats *); static void print_sfbstats(struct sfb_stats *); static void update_avg(struct if_ifclassq_stats *, struct queue_stats *); +static void print_fq_codel_stats(int slot, struct fq_codel_classstats *, + struct queue_stats *); struct queue_stats qstats[IFCQ_SC_MAX]; @@ -1064,6 +1067,8 @@ loop: sum->ift_fb - total->ift_fb); } *total = *sum; + + free(ifmsuppall); } if (!first) putchar('\n'); @@ -1468,6 +1473,11 @@ loop: print_qfqstats(n, &ifcqs->ifqs_qfq_stats, &qstats[n]); break; + case PKTSCHEDT_FQ_CODEL: + print_fq_codel_stats(n, + &ifcqs->ifqs_fq_codel_stats, + &qstats[n]); + break; case PKTSCHEDT_NONE: default: break; @@ -1699,6 +1709,35 @@ print_qfqstats(int slot, struct qfq_classstats *cs, struct queue_stats *qs) } } +static void +print_fq_codel_stats(int pri, struct fq_codel_classstats *fqst, + struct queue_stats *qs) +{ + printf(" [ pri: %s (%d)\tsrv_cl: 0x%x\tquantum: %d\tdrr_max: %d ]\n", + pri2str(fqst->fcls_pri), fqst->fcls_pri, + fqst->fcls_service_class, fqst->fcls_quantum, + fqst->fcls_drr_max); + printf(" [ budget: %lld\t\ttarget qdelay: %14s ]\n", + fqst->fcls_budget, nsec_to_str(fqst->fcls_target_qdelay)); + printf(" [ flow control: %u\tfeedback: %u\tstalls: %u\tfailed: %u ]\n", + fqst->fcls_flow_control, fqst->fcls_flow_feedback, + fqst->fcls_dequeue_stall, fqst->fcls_flow_control_fail); + printf(" [ drop overflow: %llu\tearly: %llu\tmemfail: %u\tduprexmt:%u ]\n", + fqst->fcls_drop_overflow, fqst->fcls_drop_early, + fqst->fcls_drop_memfailure, fqst->fcls_dup_rexmts); + printf(" [ flows total: %u\tnew: %u\told: %u ]\n", + fqst->fcls_flows_cnt, + fqst->fcls_newflows_cnt, fqst->fcls_oldflows_cnt); + printf(" [ queued pkts: %llu\tbytes: %llu ]\n", + fqst->fcls_pkt_cnt, fqst->fcls_byte_cnt); + printf(" [ dequeued pkts: %llu\tbytes: %llu ]\n", + fqst->fcls_dequeue, fqst->fcls_dequeue_bytes); + printf(" [ throttle on: %u\toff: %u\tdrop: %u ]\n", + fqst->fcls_throttle_on, fqst->fcls_throttle_off, + fqst->fcls_throttle_drops); + printf("=====================================================\n"); +} + static void print_sfbstats(struct sfb_stats *sfb) { @@ -1808,6 +1847,10 @@ update_avg(struct if_ifclassq_stats *ifcqs, struct queue_stats *qs) b = ifcqs->ifqs_qfq_stats.xmitcnt.bytes; p = ifcqs->ifqs_qfq_stats.xmitcnt.packets; break; + case PKTSCHEDT_FQ_CODEL: + b = ifcqs->ifqs_fq_codel_stats.fcls_dequeue_bytes; + p = ifcqs->ifqs_fq_codel_stats.fcls_dequeue; + break; default: b = 0; p = 0; @@ -1868,8 +1911,8 @@ qtype2str(classq_type_t t) } #define NSEC_PER_SEC 1000000000 /* nanoseconds per second */ -#define USEC_PER_SEC 1000000 /* nanoseconds per second */ -#define MSEC_PER_SEC 1000 /* nanoseconds per second */ +#define USEC_PER_SEC 1000000 /* microseconds per second */ +#define MSEC_PER_SEC 1000 /* milliseconds per second */ static char * nsec_to_str(unsigned long long nsec) @@ -1923,6 +1966,9 @@ sched2str(unsigned int s) case PKTSCHEDT_QFQ: c = "QFQ"; break; + case PKTSCHEDT_FQ_CODEL: + c = "FQ_CODEL"; + break; default: c = "UNKNOWN"; break; @@ -2007,6 +2053,48 @@ tcqslot2str(unsigned int s) return (c); } +static char * +pri2str(unsigned int i) +{ + char *c; + switch (i) { + case 9: + c = "BK_SYS"; + break; + case 8: + c = "BK"; + break; + case 7: + c = "BE"; + break; + case 6: + c = "RD"; + break; + case 5: + c = "OAM"; + break; + case 4: + c = "AV"; + break; + case 3: + c = "RV"; + break; + case 2: + c = "VI"; + break; + case 1: + c = "VO"; + break; + case 0: + c = "CTL"; + break; + default: + c = "?"; + break; + } + return (c); +} + static char * qstate2str(unsigned int s) { @@ -2295,8 +2383,8 @@ rem_nstat_src(int fd, nstat_src_ref_t sref) } if (remrsp->srcref != sref) { - fprintf(stderr, "%s: received invalid srcref, received %u " - "expected %u\n", __func__, remrsp->srcref, sref); + fprintf(stderr, "%s: received invalid srcref, received %llu " + "expected %llu\n", __func__, remrsp->srcref, sref); } return 0; } @@ -2352,7 +2440,7 @@ get_src_decsription(int fd, nstat_src_ref_t srcref, if (drsp->srcref != srcref) { fprintf(stderr, "%s: received message for wrong source, " - "received 0x%x expected 0x%x\n", + "received 0x%llx expected 0x%llx\n", __func__, drsp->srcref, srcref); return -1; } @@ -2427,7 +2515,7 @@ print_wifi_status(nstat_ifnet_desc_wifi_status *status) static void print_cellular_status(nstat_ifnet_desc_cellular_status *status) { - int tmp; + int tmp, tmp_mss; #define val(x, f) \ ((status->valid_bitmask & NSTAT_IFNET_DESC_CELL_ ## f ## _VALID) ?\ status->x : -1) @@ -2439,6 +2527,12 @@ print_cellular_status(nstat_ifnet_desc_cellular_status *status) ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_MEDIUM) ? "(medium)" : \ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_HIGH) ? "(high)" : \ "(?)"))))) +#define pretxtm(n, un) \ + (((tmp_mss = val(n,un)) == -1) ? "(not valid)" : \ + ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_NONE) ? "(none)" : \ + ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_MEDIUM) ? "(medium)" : \ + ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_LOW) ? "(low)" : \ + "(?)")))) printf("\ncellular status:\n"); printf( @@ -2456,7 +2550,8 @@ print_cellular_status(nstat_ifnet_desc_cellular_status *status) "\t%s:\t%d\n" "\t%s:\t%d\n" "\t%s:\t%d\n" - "\t%s:\t%d\n", + "\t%s:\t%d\n" + "\t%s:\t%d %s\n", parg(link_quality_metric, LINK_QUALITY_METRIC), parg(ul_effective_bandwidth, UL_EFFECTIVE_BANDWIDTH), parg(ul_max_bandwidth, UL_MAX_BANDWIDTH), @@ -2472,7 +2567,9 @@ print_cellular_status(nstat_ifnet_desc_cellular_status *status) parg(dl_effective_bandwidth, DL_EFFECTIVE_BANDWIDTH), parg(dl_max_bandwidth, DL_MAX_BANDWIDTH), parg(config_inactivity_time, CONFIG_INACTIVITY_TIME), - parg(config_backoff_time, CONFIG_BACKOFF_TIME) + parg(config_backoff_time, CONFIG_BACKOFF_TIME), + parg(mss_recommended, MSS_RECOMMENDED), + pretxtm(mss_recommended, MSS_RECOMMENDED) ); #undef pretxtl #undef parg diff --git a/netstat.tproj/inet.c b/netstat.tproj/inet.c index 47eeaea..d614aec 100644 --- a/netstat.tproj/inet.c +++ b/netstat.tproj/inet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2014 Apple Inc. All rights reserved. + * Copyright (c) 2008-2016 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -697,6 +697,9 @@ tcp_stats(uint32_t off , char *name, int af) p(tcps_ecn_conn_plnoce, "\t\t%u connection%s using ECN have seen packet loss but no CE\n"); p(tcps_ecn_conn_pl_ce, "\t\t%u connection%s using ECN have seen packet loss and CE\n"); p(tcps_ecn_conn_nopl_ce, "\t\t%u connection%s using ECN received CE but no packet loss\n"); + p(tcps_ecn_fallback_synloss, "\t\t%u connection%s fell back to non-ECN due to SYN-loss\n"); + p(tcps_ecn_fallback_reorder, "\t\t%u connection%s fell back to non-ECN due to reordering\n"); + p(tcps_ecn_fallback_ce, "\t\t%u connection%s fell back to non-ECN due to excessive CE-markings\n"); p(tcps_detect_reordering, "\t%u time%s packet reordering was detected on a connection\n"); p(tcps_reordered_pkts, "\t\t%u time%s transmitted packets were reordered\n"); p(tcps_delay_recovery, "\t\t%u time%s fast recovery was delayed to handle reordering\n"); @@ -721,6 +724,9 @@ tcp_stats(uint32_t off , char *name, int af) p(tcps_tfo_syn_data_acked,"\t\t%u time%s our SYN with data has been acknowledged\n"); p(tcps_tfo_syn_loss,"\t%u time%s a connection-attempt with TFO fell back to regular TCP\n"); p(tcps_tfo_blackhole,"\t%u time%s a TFO-connection blackhole'd\n"); + p(tcps_mss_to_default,"\t%u time%s maximum segment size was changed to default\n"); + p(tcps_mss_to_medium,"\t%u time%s maximum segment size was changed to medium\n"); + p(tcps_mss_to_low,"\t%u time%s maximum segment size was changed to low\n"); if (interval > 0) { bcopy(&tcpstat, &ptcpstat, len); @@ -791,10 +797,10 @@ mptcp_stats(uint32_t off , char *name, int af) p(tcps_mp_badcsum, "\t%u bad DSS checksum%s\n"); p(tcps_mp_oodata, "\t%u time%s received out of order data \n"); p3(tcps_mp_switches, "\t%u subflow switch%s\n"); - p3(tcps_mp_sel_symtomsd, "\t%u subflow switche%s due to advisory\n"); - p3(tcps_mp_sel_rtt, "\t%u subflow switche%s due to rtt\n"); - p3(tcps_mp_sel_rto, "\t%u subflow switche%s due to rto\n"); - p3(tcps_mp_sel_peer, "\t%u subflow switche%s due to peer\n"); + p3(tcps_mp_sel_symtomsd, "\t%u subflow switch%s due to advisory\n"); + p3(tcps_mp_sel_rtt, "\t%u subflow switch%s due to rtt\n"); + p3(tcps_mp_sel_rto, "\t%u subflow switch%s due to rto\n"); + p3(tcps_mp_sel_peer, "\t%u subflow switch%s due to peer\n"); p3(tcps_mp_num_probes, "\t%u number of subflow probe%s\n"); if (interval > 0) { @@ -1079,8 +1085,11 @@ arp_stats(uint32_t off, char *name, int af) printf(m, ARPDIFF(f), plural(ARPDIFF(f))) #define p2(f, m) if (ARPDIFF(f) || sflag <= 1) \ printf(m, ARPDIFF(f), pluralies(ARPDIFF(f))) +#define p3(f, m) if (ARPDIFF(f) || sflag <= 1) \ + printf(m, ARPDIFF(f), plural(ARPDIFF(f)), pluralies(ARPDIFF(f))) - p(txrequests, "\t%u ARP request%s sent\n"); + p(txrequests, "\t%u broadast ARP request%s sent\n"); + p(txurequests, "\t%u unicast ARP request%s sent\n"); p2(txreplies, "\t%u ARP repl%s sent\n"); p(txannounces, "\t%u ARP announcement%s sent\n"); p(rxrequests, "\t%u ARP request%s received\n"); @@ -1089,6 +1098,7 @@ arp_stats(uint32_t off, char *name, int af) p(txconflicts, "\t%u ARP conflict probe%s sent\n"); p(invalidreqs, "\t%u invalid ARP resolve request%s\n"); p(reqnobufs, "\t%u total packet%s dropped due to lack of memory\n"); + p3(held, "\t%u total packet%s held awaiting ARP repl%s\n"); p(dropped, "\t%u total packet%s dropped due to no ARP entry\n"); p(purged, "\t%u total packet%s dropped during ARP entry removal\n"); p2(timeouts, "\t%u ARP entr%s timed out\n"); diff --git a/netstat.tproj/inet6.c b/netstat.tproj/inet6.c index a741196..6e81df7 100644 --- a/netstat.tproj/inet6.c +++ b/netstat.tproj/inet6.c @@ -436,6 +436,7 @@ ip6_stats(uint32_t off __unused, char *name, int af __unused) p1a(ip6s_fragtimeout, "\t\t\t%llu dropped after timeout\n"); p1a(ip6s_fragoverflow, "\t\t\t%llu exceeded limit\n"); p1a(ip6s_reassembled, "\t\t\t%llu reassembled ok\n"); + p1a(ip6s_atmfrag_rcvd, "\t\t\t%llu atomic fragments received\n"); p(ip6s_delivered, "\t\t%llu packet%s for this host\n"); p(ip6s_forward, "\t\t%llu packet%s forwarded\n"); p(ip6s_cantforward, "\t\t%llu packet%s not forwardable\n"); @@ -616,7 +617,7 @@ ip6_stats(uint32_t off __unused, char *name, int af __unused) for (first = 1, i = 0; i < IP6S_SRCRULE_COUNT; i++) { if (IP6DIFF(ip6s_sources_rule[i]) || 1) { if (first) { - printf("\t\tsource addresse selection\n"); + printf("\t\tsource address selection\n"); first = 0; } PRINT_SRCRULESTAT(ip6s_sources_rule[i], i); @@ -624,8 +625,10 @@ ip6_stats(uint32_t off __unused, char *name, int af __unused) } p(ip6s_dad_collide, "\t\t%llu duplicate address detection collision%s\n"); + + p(ip6s_dad_loopcount, "\t\t%llu duplicate address detection NS loop%s\n"); - p(ip6s_sources_skip_expensive_secondary_if, "\t\t%llu times%s ignored source on secondary expensive I/F\n"); + p(ip6s_sources_skip_expensive_secondary_if, "\t\t%llu time%s ignored source on secondary expensive I/F\n"); if (interval > 0) { bcopy(&ip6stat, &pip6stat, len); @@ -684,6 +687,7 @@ ip6_ifstats(char *ifname) p(ifs6_out_fragcreat, "\t%llu output datagram%s succeeded on fragment\n"); p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n"); p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n"); + p(ifs6_atmfrag_rcvd, "\t%llu atomic fragments%s received\n"); p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembling\n"); p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n"); p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n"); @@ -1039,6 +1043,7 @@ icmp6_stats(uint32_t off __unused, char *name, int af __unused) p(icp6s_badra, "\t%qu bad router advertisement message%s\n"); p(icp6s_badredirect, "\t%qu bad redirect message%s\n"); p(icp6s_pmtuchg, "\t%llu path MTU change%s\n"); + p(icp6s_rfc6980_drop, "\t%qu dropped fragmented NDP message%s\n"); if (interval > 0) bcopy(&icmp6stat, &picmp6stat, len); @@ -1145,7 +1150,7 @@ rip6_stats(uint32_t off __unused, char *name, int af __unused) #define p(f, m) if (RIP6DIFF(f) || sflag <= 1) \ printf(m, (unsigned long long)RIP6DIFF(f), plural(RIP6DIFF(f))) p(rip6s_ipackets, "\t%llu message%s received\n"); - p(rip6s_isum, "\t%llu checksum calcuration%s on inbound\n"); + p(rip6s_isum, "\t%llu checksum calculation%s on inbound\n"); p(rip6s_badsum, "\t%llu message%s with bad checksum\n"); p(rip6s_nosock, "\t%llu message%s dropped due to no socket\n"); p(rip6s_nosockmcast, @@ -1208,7 +1213,7 @@ inet6print(struct in6_addr *in6, int port, char *proto, int numeric) if (!numeric && port) GETSERVBYPORT6(port, proto, sp); if (sp || port == 0) - snprintf(cp, sizeof(line) - (cp - line), "%.8s", sp ? sp->s_name : "*"); + snprintf(cp, sizeof(line) - (cp - line), "%.15s", sp ? sp->s_name : "*"); else snprintf(cp, sizeof(line) - (cp - line), "%d", ntohs((u_short)port)); width = lflag ? 45 : Aflag ? 18 : 22; diff --git a/netstat.tproj/mptcp.c b/netstat.tproj/mptcp.c index 4d69770..b3e13ff 100644 --- a/netstat.tproj/mptcp.c +++ b/netstat.tproj/mptcp.c @@ -57,7 +57,7 @@ static const char *tcpstates[] = { static const char *mptcpstates[] = { "CLOSED", "LISTEN", "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", - "CLOSING", "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", "FASTCLOSE_WAIT" + "CLOSING", "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", "TERMINATE" }; int mptcp_done = 0; diff --git a/netstat.tproj/systm.c b/netstat.tproj/systm.c index a3c170e..d94dec0 100644 --- a/netstat.tproj/systm.c +++ b/netstat.tproj/systm.c @@ -377,7 +377,7 @@ kevt_stats(uint32_t off __unused, char *name, int af __unused) { static struct kevtstat pkevtstat; struct kevtstat kevtstat; - size_t len = sizeof(struct kctlstat); + size_t len = sizeof(struct kevtstat); const char *mibvar = "net.systm.kevt.stats"; if (sysctlbyname(mibvar, &kevtstat, &len, 0, 0) < 0) { diff --git a/netstat.tproj/unix.c b/netstat.tproj/unix.c index 2154809..2c7b2ef 100644 --- a/netstat.tproj/unix.c +++ b/netstat.tproj/unix.c @@ -86,7 +86,7 @@ static void unixdomainpr __P((struct xunpcb *, struct xsocket *)); #endif static const char *const socktype[] = - { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" }; + { "#0", "stream", "dgram", "raw" }; void unixpr() @@ -105,7 +105,7 @@ unixpr() char mibvar[sizeof "net.local.seqpacket.pcblist"]; #endif - for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) { + for (type = SOCK_STREAM; type <= SOCK_RAW; type++) { #if !TARGET_OS_EMBEDDED snprintf(mibvar, sizeof(mibvar), "net.local.%s.pcblist64", socktype[type]); #else diff --git a/network_cmds.xcodeproj/project.pbxproj b/network_cmds.xcodeproj/project.pbxproj index d7b9d4c..511810c 100755 --- a/network_cmds.xcodeproj/project.pbxproj +++ b/network_cmds.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 72B732EB1899B19A0060E6D4 /* PBXTargetDependency */, 72179EAE146233390098FB3E /* PBXTargetDependency */, 7282BA571AFBDEAD005DE836 /* PBXTargetDependency */, + 72946F4C1BBF063800087E35 /* PBXTargetDependency */, 034E4469100BDD00009CA3DC /* PBXTargetDependency */, 565825AF13392239003E5FA5 /* PBXTargetDependency */, 72311F4D194A34F500EB4788 /* PBXTargetDependency */, @@ -46,6 +47,7 @@ 72B732E91899B18F0060E6D4 /* PBXTargetDependency */, 723C7074142BB003007C87E9 /* PBXTargetDependency */, 7282BA5B1AFBDED3005DE836 /* PBXTargetDependency */, + 7263724B1BCC709900E4B026 /* PBXTargetDependency */, 7261217D0EE8896800AFED1B /* PBXTargetDependency */, 4D2B05141208C6BB0004A3F3 /* PBXTargetDependency */, 724DABC30EE890A6008900D0 /* PBXTargetDependency */, @@ -79,6 +81,7 @@ 72ABD0A41083D818008C721C /* PBXTargetDependency */, 72ABD0881083D750008C721C /* PBXTargetDependency */, 7282BA591AFBDEC2005DE836 /* PBXTargetDependency */, + 72946F4E1BBF063F00087E35 /* PBXTargetDependency */, 565825B113392242003E5FA5 /* PBXTargetDependency */, 72311F4F194A34FE00EB4788 /* PBXTargetDependency */, 690D97BA12DE7130004323A7 /* PBXTargetDependency */, @@ -243,12 +246,10 @@ 72311F55194A354F00EB4788 /* mptcp_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 72311F53194A354F00EB4788 /* mptcp_client.c */; }; 72311F56194A76DA00EB4788 /* mptcp_client.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 72311F52194A354F00EB4788 /* mptcp_client.1 */; }; 724753E7144905E300F6A941 /* dnctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 724753E61448E1EF00F6A941 /* dnctl.8 */; }; + 724769371CE2B1FF00AAB5F0 /* gmt2local.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3C1AFAD58E005DE836 /* gmt2local.c */; }; + 724769381CE2C1E400AAB5F0 /* gmt2local.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3C1AFAD58E005DE836 /* gmt2local.c */; }; 7247B83616165EDC00873B3C /* pktapctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7247B83516165EDC00873B3C /* pktapctl.8 */; }; 7247B83C16165F0100873B3C /* pktapctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 7247B83B16165F0100873B3C /* pktapctl.c */; }; - 724DAB640EE88E63008900D0 /* ipfw2.c in Sources */ = {isa = PBXBuildFile; fileRef = 726121000EE8701100AFED1B /* ipfw2.c */; }; - 724DAB680EE88E78008900D0 /* ipfw.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120FF0EE8701100AFED1B /* ipfw.8 */; }; - 724DAB860EE88F0D008900D0 /* ip6fw.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120690EE86F2300AFED1B /* ip6fw.c */; }; - 724DAB8A0EE88F24008900D0 /* ip6fw.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120680EE86F2300AFED1B /* ip6fw.8 */; }; 724DABA60EE88FED008900D0 /* kdumpd.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120710EE86F2D00AFED1B /* kdumpd.c */; }; 724DABA70EE88FED008900D0 /* kdumpsubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120720EE86F2D00AFED1B /* kdumpsubs.c */; }; 724DABAB0EE89006008900D0 /* kdumpd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120700EE86F2D00AFED1B /* kdumpd.8 */; }; @@ -286,6 +287,7 @@ 7282BA521AFAD58E005DE836 /* session.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA451AFAD58E005DE836 /* session.c */; }; 7282BA531AFAD58E005DE836 /* support.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA471AFAD58E005DE836 /* support.c */; }; 7282BA551AFBCA66005DE836 /* libpcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7282BA541AFBCA66005DE836 /* libpcap.dylib */; }; + 72946F501BBF07FF00087E35 /* frame_delay.c in Sources */ = {isa = PBXBuildFile; fileRef = 72946F4F1BBF07FF00087E35 /* frame_delay.c */; }; 7294F0DF0EE8BA730052EC88 /* spray.x in Sources */ = {isa = PBXBuildFile; fileRef = 726120E10EE86F9D00AFED1B /* spray.x */; }; 7294F1000EE8BB990052EC88 /* as.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120E50EE86FA700AFED1B /* as.c */; }; 7294F1010EE8BB990052EC88 /* findsaddr-socket.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120E70EE86FA700AFED1B /* findsaddr-socket.c */; }; @@ -612,6 +614,13 @@ remoteGlobalIDString = 726121530EE8881700AFED1B; remoteInfo = ifconfig; }; + 7263724A1BCC709900E4B026 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 724862310EE86EB7001D0DE9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 72946F421BBF055700087E35; + remoteInfo = frame_delay; + }; 7282BA561AFBDEAD005DE836 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 724862310EE86EB7001D0DE9 /* Project object */; @@ -633,6 +642,20 @@ remoteGlobalIDString = 7282BA0B1AFAD4C9005DE836; remoteInfo = ecnprobe; }; + 72946F4B1BBF063800087E35 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 724862310EE86EB7001D0DE9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 72946F421BBF055700087E35; + remoteInfo = frame_delay; + }; + 72946F4D1BBF063F00087E35 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 724862310EE86EB7001D0DE9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 72946F421BBF055700087E35; + remoteInfo = frame_delay; + }; 7294F0E90EE8BAC80052EC88 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 724862310EE86EB7001D0DE9 /* Project object */; @@ -972,26 +995,6 @@ ); runOnlyForDeploymentPostprocessing = 1; }; - 724DAB760EE88E9C008900D0 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 8; - dstPath = /usr/share/man/man8; - dstSubfolderSpec = 0; - files = ( - 724DAB680EE88E78008900D0 /* ipfw.8 in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 724DAB970EE88F56008900D0 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 8; - dstPath = /usr/share/man/man8; - dstSubfolderSpec = 0; - files = ( - 724DAB8A0EE88F24008900D0 /* ip6fw.8 in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 1; - }; 724DABB70EE89035008900D0 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; @@ -1061,6 +1064,15 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 72946F411BBF055700087E35 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; 7294F11A0EE8BC0C0052EC88 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; @@ -1281,8 +1293,6 @@ 7247B83116165EDC00873B3C /* pktapctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pktapctl; sourceTree = BUILT_PRODUCTS_DIR; }; 7247B83516165EDC00873B3C /* pktapctl.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = pktapctl.8; sourceTree = ""; }; 7247B83B16165F0100873B3C /* pktapctl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pktapctl.c; sourceTree = ""; }; - 724DAB5F0EE88E2A008900D0 /* ipfw */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ipfw; sourceTree = BUILT_PRODUCTS_DIR; }; - 724DAB820EE88EFA008900D0 /* ip6fw */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ip6fw; sourceTree = BUILT_PRODUCTS_DIR; }; 724DABA20EE88FE3008900D0 /* kdumpd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = kdumpd; sourceTree = BUILT_PRODUCTS_DIR; }; 724DABDB0EE8912D008900D0 /* natd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = natd; sourceTree = BUILT_PRODUCTS_DIR; }; 724DAC0D0EE8940D008900D0 /* ndp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ndp; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1305,8 +1315,6 @@ 726120580EE86F0900AFED1B /* ifconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ifconfig.h; sourceTree = ""; }; 726120590EE86F0900AFED1B /* ifmedia.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifmedia.c; sourceTree = ""; }; 7261205A0EE86F0900AFED1B /* ifvlan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifvlan.c; sourceTree = ""; }; - 726120680EE86F2300AFED1B /* ip6fw.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ip6fw.8; sourceTree = ""; }; - 726120690EE86F2300AFED1B /* ip6fw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ip6fw.c; sourceTree = ""; }; 7261206E0EE86F2D00AFED1B /* com.apple.kdumpd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.kdumpd.plist; sourceTree = ""; }; 7261206F0EE86F2D00AFED1B /* kdump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kdump.h; sourceTree = ""; }; 726120700EE86F2D00AFED1B /* kdumpd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = kdumpd.8; sourceTree = ""; }; @@ -1340,7 +1348,6 @@ 7261209B0EE86F4800AFED1B /* unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unix.c; sourceTree = ""; }; 726120A00EE86F5000AFED1B /* ping.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ping.8; sourceTree = ""; }; 726120A10EE86F5000AFED1B /* ping.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ping.c; sourceTree = ""; }; - 726120A50EE86F5C00AFED1B /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; 726120A60EE86F5C00AFED1B /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = md5.c; sourceTree = ""; }; 726120A70EE86F5C00AFED1B /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md5.h; sourceTree = ""; }; 726120A80EE86F5C00AFED1B /* ping6.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ping6.8; sourceTree = ""; }; @@ -1395,17 +1402,15 @@ 726120F10EE86FA700AFED1B /* traceroute.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = traceroute.c; sourceTree = ""; }; 726120F20EE86FA700AFED1B /* traceroute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = traceroute.h; sourceTree = ""; }; 726120F30EE86FA700AFED1B /* version.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = version.c; sourceTree = ""; }; - 726120F90EE86FB500AFED1B /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; 726120FA0EE86FB500AFED1B /* traceroute6.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = traceroute6.8; sourceTree = ""; }; 726120FB0EE86FB500AFED1B /* traceroute6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = traceroute6.c; sourceTree = ""; }; - 726120FF0EE8701100AFED1B /* ipfw.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ipfw.8; sourceTree = ""; }; - 726121000EE8701100AFED1B /* ipfw2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ipfw2.c; sourceTree = ""; }; 7261210C0EE8707500AFED1B /* libalias.A.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libalias.A.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 726121220EE870D400AFED1B /* alias_local.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alias_local.h; sourceTree = ""; }; 726121230EE870D400AFED1B /* alias.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alias.h; sourceTree = ""; }; 726121240EE870D400AFED1B /* libalias.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = libalias.3; sourceTree = ""; }; 7261212D0EE8710B00AFED1B /* arp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = arp; sourceTree = BUILT_PRODUCTS_DIR; }; 726121540EE8881700AFED1B /* ifconfig */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ifconfig; sourceTree = BUILT_PRODUCTS_DIR; }; + 7263724C1BCC718B00E4B026 /* frame_delay.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = frame_delay.8; sourceTree = ""; }; 7282BA0C1AFAD4C9005DE836 /* ecnprobe */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ecnprobe; sourceTree = BUILT_PRODUCTS_DIR; }; 7282BA341AFAD58E005DE836 /* base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base.h; sourceTree = ""; }; 7282BA351AFAD58E005DE836 /* capture.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = capture.c; sourceTree = ""; }; @@ -1425,6 +1430,8 @@ 7282BA481AFAD58E005DE836 /* support.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = support.h; sourceTree = ""; }; 7282BA541AFBCA66005DE836 /* libpcap.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpcap.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/lib/libpcap.dylib; sourceTree = DEVELOPER_DIR; }; 7282BA5C1AFBED07005DE836 /* ecnprobe.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = ecnprobe.1; sourceTree = ""; }; + 72946F431BBF055700087E35 /* frame_delay */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = frame_delay; sourceTree = BUILT_PRODUCTS_DIR; }; + 72946F4F1BBF07FF00087E35 /* frame_delay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = frame_delay.c; sourceTree = ""; }; 7294F0F90EE8BB460052EC88 /* traceroute */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = traceroute; sourceTree = BUILT_PRODUCTS_DIR; }; 7294F12A0EE8BD280052EC88 /* traceroute6 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = traceroute6; sourceTree = BUILT_PRODUCTS_DIR; }; 72B732DA1899B0380060E6D4 /* cfilutil */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cfilutil; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1552,20 +1559,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 724DAB5D0EE88E2A008900D0 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 724DAB800EE88EFA008900D0 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 724DABA00EE88FE3008900D0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1617,6 +1610,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 72946F401BBF055700087E35 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 7294F0F70EE8BB460052EC88 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1982,10 +1982,9 @@ 72B732DB1899B0380060E6D4 /* cfilutil */, 723C706A142BAFEA007C87E9 /* dnctl */, 7282BA0D1AFAD4C9005DE836 /* ecnprobe */, + 72946F441BBF055700087E35 /* frame_delay */, 726120540EE86F0900AFED1B /* ifconfig.tproj */, 4D2B04E31208C12F0004A3F3 /* ip6addrctl.tproj */, - 726120670EE86F2300AFED1B /* ip6fw.tproj */, - 726120FE0EE8701100AFED1B /* ipfw.tproj */, 7261206D0EE86F2D00AFED1B /* kdumpd.tproj */, 56582591133920B5003E5FA5 /* mnc.tproj */, 72311F43194A349100EB4788 /* mptcp_client */, @@ -2058,15 +2057,6 @@ path = ifconfig.tproj; sourceTree = ""; }; - 726120670EE86F2300AFED1B /* ip6fw.tproj */ = { - isa = PBXGroup; - children = ( - 726120680EE86F2300AFED1B /* ip6fw.8 */, - 726120690EE86F2300AFED1B /* ip6fw.c */, - ); - path = ip6fw.tproj; - sourceTree = ""; - }; 7261206D0EE86F2D00AFED1B /* kdumpd.tproj */ = { isa = PBXGroup; children = ( @@ -2140,7 +2130,6 @@ 726120A40EE86F5C00AFED1B /* ping6.tproj */ = { isa = PBXGroup; children = ( - 726120A50EE86F5C00AFED1B /* Makefile */, 726120A60EE86F5C00AFED1B /* md5.c */, 726120A70EE86F5C00AFED1B /* md5.h */, 726120A80EE86F5C00AFED1B /* ping6.8 */, @@ -2244,30 +2233,18 @@ 726120F80EE86FB500AFED1B /* traceroute6.tproj */ = { isa = PBXGroup; children = ( - 726120F90EE86FB500AFED1B /* Makefile */, 726120FA0EE86FB500AFED1B /* traceroute6.8 */, 726120FB0EE86FB500AFED1B /* traceroute6.c */, ); path = traceroute6.tproj; sourceTree = ""; }; - 726120FE0EE8701100AFED1B /* ipfw.tproj */ = { - isa = PBXGroup; - children = ( - 726120FF0EE8701100AFED1B /* ipfw.8 */, - 726121000EE8701100AFED1B /* ipfw2.c */, - ); - path = ipfw.tproj; - sourceTree = ""; - }; 7261210D0EE8707500AFED1B /* Products */ = { isa = PBXGroup; children = ( 7261210C0EE8707500AFED1B /* libalias.A.dylib */, 7261212D0EE8710B00AFED1B /* arp */, 726121540EE8881700AFED1B /* ifconfig */, - 724DAB5F0EE88E2A008900D0 /* ipfw */, - 724DAB820EE88EFA008900D0 /* ip6fw */, 724DABA20EE88FE3008900D0 /* kdumpd */, 724DABDB0EE8912D008900D0 /* natd */, 724DAC0D0EE8940D008900D0 /* ndp */, @@ -2291,6 +2268,7 @@ 7200F2FA1958A34D0033E22C /* pktmnglr */, 713297681A93C743002359CF /* unbound */, 7282BA0C1AFAD4C9005DE836 /* ecnprobe */, + 72946F431BBF055700087E35 /* frame_delay */, ); name = Products; sourceTree = ""; @@ -2319,6 +2297,15 @@ path = ecnprobe; sourceTree = ""; }; + 72946F441BBF055700087E35 /* frame_delay */ = { + isa = PBXGroup; + children = ( + 72946F4F1BBF07FF00087E35 /* frame_delay.c */, + 7263724C1BCC718B00E4B026 /* frame_delay.8 */, + ); + path = frame_delay; + sourceTree = ""; + }; 72B732DB1899B0380060E6D4 /* cfilutil */ = { isa = PBXGroup; children = ( @@ -2630,42 +2617,6 @@ productReference = 7247B83116165EDC00873B3C /* pktapctl */; productType = "com.apple.product-type.tool"; }; - 724DAB5E0EE88E2A008900D0 /* ipfw */ = { - isa = PBXNativeTarget; - buildConfigurationList = 724DAB770EE88E9C008900D0 /* Build configuration list for PBXNativeTarget "ipfw" */; - buildPhases = ( - 724DAB5C0EE88E2A008900D0 /* Sources */, - 724DAB5D0EE88E2A008900D0 /* Frameworks */, - 724DAB760EE88E9C008900D0 /* CopyFiles */, - 72CD1DB00EE8C551005F825D /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ipfw; - productName = ipfw; - productReference = 724DAB5F0EE88E2A008900D0 /* ipfw */; - productType = "com.apple.product-type.tool"; - }; - 724DAB810EE88EFA008900D0 /* ip6fw */ = { - isa = PBXNativeTarget; - buildConfigurationList = 724DAB980EE88F56008900D0 /* Build configuration list for PBXNativeTarget "ip6fw" */; - buildPhases = ( - 724DAB7F0EE88EFA008900D0 /* Sources */, - 724DAB800EE88EFA008900D0 /* Frameworks */, - 724DAB970EE88F56008900D0 /* CopyFiles */, - 724DAC1B0EE89440008900D0 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ip6fw; - productName = ip6fw; - productReference = 724DAB820EE88EFA008900D0 /* ip6fw */; - productType = "com.apple.product-type.tool"; - }; 724DABA10EE88FE3008900D0 /* kdumpd */ = { isa = PBXNativeTarget; buildConfigurationList = 724DABB80EE89035008900D0 /* Build configuration list for PBXNativeTarget "kdumpd" */; @@ -2792,6 +2743,23 @@ productReference = 7282BA0C1AFAD4C9005DE836 /* ecnprobe */; productType = "com.apple.product-type.tool"; }; + 72946F421BBF055700087E35 /* frame_delay */ = { + isa = PBXNativeTarget; + buildConfigurationList = 72946F4A1BBF055700087E35 /* Build configuration list for PBXNativeTarget "frame_delay" */; + buildPhases = ( + 72946F3F1BBF055700087E35 /* Sources */, + 72946F401BBF055700087E35 /* Frameworks */, + 72946F411BBF055700087E35 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = frame_delay; + productName = frame_delay; + productReference = 72946F431BBF055700087E35 /* frame_delay */; + productType = "com.apple.product-type.tool"; + }; 7294F0F80EE8BB460052EC88 /* traceroute */ = { isa = PBXNativeTarget; buildConfigurationList = 7294F0FD0EE8BB550052EC88 /* Build configuration list for PBXNativeTarget "traceroute" */; @@ -2851,7 +2819,7 @@ 724862310EE86EB7001D0DE9 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0500; + LastUpgradeCheck = 0800; TargetAttributes = { 713297671A93C743002359CF = { CreatedOnToolsVersion = 6.3; @@ -2865,6 +2833,9 @@ 7282BA0B1AFAD4C9005DE836 = { CreatedOnToolsVersion = 7.0; }; + 72946F421BBF055700087E35 = { + CreatedOnToolsVersion = 6.3; + }; }; }; buildConfigurationList = 724862340EE86EB7001D0DE9 /* Build configuration list for PBXProject "network_cmds" */; @@ -2891,10 +2862,9 @@ 72B732D91899B0380060E6D4 /* cfilutil */, 723C7067142BAFEA007C87E9 /* dnctl */, 7282BA0B1AFAD4C9005DE836 /* ecnprobe */, + 72946F421BBF055700087E35 /* frame_delay */, 726121530EE8881700AFED1B /* ifconfig */, 4D2B04F21208C2040004A3F3 /* ip6addrctl */, - 724DAB810EE88EFA008900D0 /* ip6fw */, - 724DAB5E0EE88E2A008900D0 /* ipfw */, 724DABA10EE88FE3008900D0 /* kdumpd */, 5658259E1339218F003E5FA5 /* mnc */, 72311F41194A349000EB4788 /* mptcp_client */, @@ -3091,19 +3061,6 @@ shellPath = /bin/sh; shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/natd.8\t"; }; - 724DAC1B0EE89440008900D0 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 8; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 1; - shellPath = /bin/sh; - shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/ip6fw.8\t"; - }; 724DAC440EE89562008900D0 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 8; @@ -3182,19 +3139,6 @@ shellPath = /bin/sh; shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/ifconfig.8\t"; }; - 72CD1DB00EE8C551005F825D /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 8; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 1; - shellPath = /bin/sh; - shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/ipfw.8\n"; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -3334,6 +3278,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 724769381CE2C1E400AAB5F0 /* gmt2local.c in Sources */, 7216D2800EE8981C00AE70E4 /* ping.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3342,6 +3287,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 724769371CE2B1FF00AAB5F0 /* gmt2local.c in Sources */, 7216D2A00EE898DF00AE70E4 /* md5.c in Sources */, 7216D2A10EE898DF00AE70E4 /* ping6.c in Sources */, ); @@ -3424,22 +3370,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 724DAB5C0EE88E2A008900D0 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 724DAB640EE88E63008900D0 /* ipfw2.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 724DAB7F0EE88EFA008900D0 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 724DAB860EE88F0D008900D0 /* ip6fw.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 724DAB9F0EE88FE3008900D0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -3522,6 +3452,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 72946F3F1BBF055700087E35 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 72946F501BBF07FF00087E35 /* frame_delay.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 7294F0F60EE8BB460052EC88 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -3759,6 +3697,11 @@ target = 726121530EE8881700AFED1B /* ifconfig */; targetProxy = 7261217C0EE8896800AFED1B /* PBXContainerItemProxy */; }; + 7263724B1BCC709900E4B026 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 72946F421BBF055700087E35 /* frame_delay */; + targetProxy = 7263724A1BCC709900E4B026 /* PBXContainerItemProxy */; + }; 7282BA571AFBDEAD005DE836 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 7282BA0B1AFAD4C9005DE836 /* ecnprobe */; @@ -3774,6 +3717,16 @@ target = 7282BA0B1AFAD4C9005DE836 /* ecnprobe */; targetProxy = 7282BA5A1AFBDED3005DE836 /* PBXContainerItemProxy */; }; + 72946F4C1BBF063800087E35 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 72946F421BBF055700087E35 /* frame_delay */; + targetProxy = 72946F4B1BBF063800087E35 /* PBXContainerItemProxy */; + }; + 72946F4E1BBF063F00087E35 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 72946F421BBF055700087E35 /* frame_delay */; + targetProxy = 72946F4D1BBF063F00087E35 /* PBXContainerItemProxy */; + }; 7294F0EA0EE8BAC80052EC88 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 7216D3A60EE8A3BA00AE70E4 /* spray */; @@ -3977,38 +3930,6 @@ }; name = "Ignore Me"; }; - 03B2DBE9100BE71D005349BC /* Ignore Me */ = { - isa = XCBuildConfiguration; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - IP_FW_PRIVATE, - ); - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_GROUP = wheel; - INSTALL_MODE_FLAG = 0555; - INSTALL_OWNER = root; - INSTALL_PATH = /sbin; - PRODUCT_NAME = ipfw; - }; - name = "Ignore Me"; - }; - 03B2DBEA100BE71D005349BC /* Ignore Me */ = { - isa = XCBuildConfiguration; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - IP_FW_PRIVATE, - ); - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_GROUP = wheel; - INSTALL_MODE_FLAG = 0555; - INSTALL_OWNER = root; - INSTALL_PATH = /sbin; - PRODUCT_NAME = ip6fw; - }; - name = "Ignore Me"; - }; 03B2DBEB100BE71D005349BC /* Ignore Me */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4085,7 +4006,6 @@ INSTALL_OWNER = root; INSTALL_PATH = /sbin; PRODUCT_NAME = ping; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; }; name = "Ignore Me"; }; @@ -4524,7 +4444,6 @@ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; MACOSX_DEPLOYMENT_TARGET = 10.10; METAL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -4632,13 +4551,18 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist"; CODE_SIGN_IDENTITY = "-"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "USE_RFC2292BIS=1", + "__APPLE_USE_RFC_3542=1", + "__APPLE_API_OBSOLETE=1", + "DEBUG=1", + ); HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; INSTALL_GROUP = wheel; INSTALL_MODE_FLAG = 0555; INSTALL_OWNER = root; INSTALL_PATH = /sbin; PRODUCT_NAME = ping; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; }; name = Debug; }; @@ -4653,7 +4577,6 @@ INSTALL_OWNER = root; INSTALL_PATH = /sbin; PRODUCT_NAME = ping; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; }; name = Release; }; @@ -4905,7 +4828,6 @@ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; MACOSX_DEPLOYMENT_TARGET = 10.10; METAL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -4940,7 +4862,6 @@ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; MACOSX_DEPLOYMENT_TARGET = 10.10; METAL_ENABLE_DEBUG_INFO = NO; - ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -4975,7 +4896,6 @@ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; MACOSX_DEPLOYMENT_TARGET = 10.10; METAL_ENABLE_DEBUG_INFO = NO; - ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = "Ignore Me"; @@ -5069,8 +4989,10 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPRESSION = lossless; COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = YES; + ENABLE_TESTABILITY = YES; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; @@ -5086,7 +5008,6 @@ ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; - ONLY_ACTIVE_ARCH = YES; PREBINDING = NO; SDKROOT = macosx.internal; SUPPORTED_PLATFORMS = "macosx iphoneos"; @@ -5098,6 +5019,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPRESSION = "respect-asset-catalog"; COPY_PHASE_STRIP = YES; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -5124,70 +5046,6 @@ }; name = Release; }; - 724DAB610EE88E2B008900D0 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - IP_FW_PRIVATE, - ); - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_GROUP = wheel; - INSTALL_MODE_FLAG = 0555; - INSTALL_OWNER = root; - INSTALL_PATH = /sbin; - PRODUCT_NAME = ipfw; - }; - name = Debug; - }; - 724DAB620EE88E2B008900D0 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - IP_FW_PRIVATE, - ); - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_GROUP = wheel; - INSTALL_MODE_FLAG = 0555; - INSTALL_OWNER = root; - INSTALL_PATH = /sbin; - PRODUCT_NAME = ipfw; - }; - name = Release; - }; - 724DAB840EE88EFA008900D0 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - IP_FW_PRIVATE, - ); - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_GROUP = wheel; - INSTALL_MODE_FLAG = 0555; - INSTALL_OWNER = root; - INSTALL_PATH = /sbin; - PRODUCT_NAME = ip6fw; - }; - name = Debug; - }; - 724DAB850EE88EFA008900D0 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - IP_FW_PRIVATE, - ); - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_GROUP = wheel; - INSTALL_MODE_FLAG = 0555; - INSTALL_OWNER = root; - INSTALL_PATH = /sbin; - PRODUCT_NAME = ip6fw; - }; - name = Release; - }; 724DABA40EE88FE3008900D0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5551,6 +5409,111 @@ }; name = "Ignore Me"; }; + 72946F471BBF055700087E35 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist"; + CODE_SIGN_IDENTITY = "-"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.11.xctoolchain/usr/include, + /System/Library/Frameworks/System.framework/PrivateHeaders, + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 72946F481BBF055700087E35 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist"; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.11.xctoolchain/usr/include, + /System/Library/Frameworks/System.framework/PrivateHeaders, + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 72946F491BBF055700087E35 /* Ignore Me */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist"; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.11.xctoolchain/usr/include, + /System/Library/Frameworks/System.framework/PrivateHeaders, + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = "Ignore Me"; + }; 7294F0FB0EE8BB460052EC88 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5973,26 +5936,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 724DAB770EE88E9C008900D0 /* Build configuration list for PBXNativeTarget "ipfw" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 724DAB610EE88E2B008900D0 /* Debug */, - 724DAB620EE88E2B008900D0 /* Release */, - 03B2DBE9100BE71D005349BC /* Ignore Me */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 724DAB980EE88F56008900D0 /* Build configuration list for PBXNativeTarget "ip6fw" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 724DAB840EE88EFA008900D0 /* Debug */, - 724DAB850EE88EFA008900D0 /* Release */, - 03B2DBEA100BE71D005349BC /* Ignore Me */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 724DABB80EE89035008900D0 /* Build configuration list for PBXNativeTarget "kdumpd" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -6083,6 +6026,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 72946F4A1BBF055700087E35 /* Build configuration list for PBXNativeTarget "frame_delay" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 72946F471BBF055700087E35 /* Debug */, + 72946F481BBF055700087E35 /* Release */, + 72946F491BBF055700087E35 /* Ignore Me */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 7294F0FD0EE8BB550052EC88 /* Build configuration list for PBXNativeTarget "traceroute" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/ping.tproj/ping.8 b/ping.tproj/ping.8 index 6c60dee..defb856 100644 --- a/ping.tproj/ping.8 +++ b/ping.tproj/ping.8 @@ -71,6 +71,7 @@ packets to network hosts .Op Fl h Ar sweepincrsize .Op Fl i Ar wait .Op Fl k Ar trafficclass +.Op Fl K Ar netservicetype .Op Fl l Ar preload .Op Fl M Cm mask | time .Op Fl m Ar ttl @@ -81,6 +82,8 @@ packets to network hosts .Op Fl t Ar timeout .Op Fl W Ar waittime .Op Fl z Ar tos +.Op Fl Fl apple-connect +.Op Fl Fl apple-print .Ar host .Nm .Op Fl AaDdfLnoQqRrv @@ -89,6 +92,7 @@ packets to network hosts .Op Fl I Ar iface .Op Fl i Ar wait .Op Fl k Ar trafficclass +.Op Fl K Ar netservicetype .Op Fl l Ar preload .Op Fl M Cm mask | time .Op Fl m Ar ttl @@ -100,6 +104,8 @@ packets to network hosts .Op Fl t Ar timeout .Op Fl W Ar waittime .Op Fl z Ar tos +.Op Fl Fl apple-connect +.Op Fl Fl apple-print .Ar mcast-group .Sh DESCRIPTION The @@ -145,8 +151,10 @@ if other format options are present. Bind the socket to interface .Ar boundif for sending. +This option is an Apple addition. .It Fl C Prohibit the socket from using the cellular network interface. +This option is an Apple addition. .It Fl c Ar count Stop after sending (and receiving) @@ -212,13 +220,19 @@ values less than 0.1 second. This option is incompatible with the .Fl f option. -.It Fl k Ar trafficlass +.It Fl k Ar trafficclass Specifies the traffic class to use for sending ICMP packets. The supported traffic classes are BK_SYS, BK, BE, RD, OAM, AV, RV, VI, VO and CTL. By default .Nm uses the control traffic class (CTL). +This option is an Apple addition. +.It Fl K Ar netservicetype +Specifies the network service type to use for sending ICMP packets. +The supported network service type are BK_SYS, BK, BE, RV, AV, RD, OAM, VI, SIG and VO. +Note this overrides the default traffic class (-k can still be specified after -K to use both). +This option is an Apple addition. .It Fl L Suppress loopback of multicast packets. This flag only applies if the ping destination is a multicast address. @@ -355,6 +369,12 @@ If a reply arrives later, the packet is not printed as replied, but considered as replied when calculating statistics. .It Fl z Ar tos Use the specified type of service. +.It Fl Fl apple-connect +Connects the socket to the destination address. +This option is an Apple addition. +.It Fl Fl apple-print +Prints the time a packet was received. +This option is an Apple addition. .El .Pp When using diff --git a/ping.tproj/ping.c b/ping.tproj/ping.c index fa79b60..ad5ea7a 100644 --- a/ping.tproj/ping.c +++ b/ping.tproj/ping.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2015 Apple Inc. All rights reserved. + * Copyright (c) 1999-2016 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -107,12 +107,14 @@ __unused static const char copyright[] = #include #include #include +#include #include #include #include #include #include #include +#include #define INADDR_LEN ((int)sizeof(in_addr_t)) #define TIMEVAL_LEN ((int)sizeof(struct tv32)) @@ -167,6 +169,8 @@ int options; #define F_TIME 0x100000 #define F_SWEEP 0x200000 #define F_WAITTIME 0x400000 +#define F_CONNECT 0x800000 +#define F_PRTIME 0x1000000 /* * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum @@ -195,12 +199,11 @@ int phdr_len = 0; int send_len; char *boundif; unsigned int ifscope; -#if defined(IP_FORCE_OUT_IFP) && TARGET_OS_EMBEDDED -char boundifname[IFNAMSIZ]; -#endif /* IP_FORCE_OUT_IFP */ int nocell; -int how_traffic_class = 0; +int use_sendmsg = 0; +int use_recvmsg = 0; int traffic_class = SO_TC_CTL; /* use control class, by default */ +int net_service_type = -1; int no_dup = 0; /* counters */ @@ -244,9 +247,26 @@ static void pr_retip(struct ip *); static void status(int); static void stopit(int); static void tvsub(struct timeval *, const struct timeval *); -static uint32_t str2svc(const char *); +static int str2sotc(const char *, bool *); +static int str2netservicetype(const char *, bool *); +static u_int8_t str2tos(const char *, bool *); static void usage(void) __dead2; +int32_t thiszone; /* seconds offset from gmt to local time */ +extern int32_t gmt2local(time_t); +static void pr_currenttime(void); + +static int longopt_flag = 0; + +#define LOF_CONNECT 0x01 +#define LOF_PRTIME 0x02 + +static const struct option longopts[] = { + { "apple-connect", no_argument, &longopt_flag, LOF_CONNECT }, + { "apple-time", no_argument, &longopt_flag, LOF_PRTIME }, + { NULL, 0, NULL, 0 } +}; + int main(int argc, char *const *argv) { @@ -280,6 +300,7 @@ main(int argc, char *const *argv) #ifdef IPSEC_POLICY_IPSEC policy_in = policy_out = NULL; #endif + bool valid; /* * Do the stuff that we need root priv's for *first*, and @@ -299,17 +320,9 @@ main(int argc, char *const *argv) alarmtimeout = df = preload = tos = 0; outpack = outpackhdr + sizeof(struct ip); - while ((ch = getopt(argc, argv, - "Aab:Cc:DdfG:g:h:I:i:k:Ll:M:m:nop:QqRrS:s:T:t:vW:z:" -#ifdef IPSEC -#ifdef IPSEC_POLICY_IPSEC - "P:" -#endif /*IPSEC_POLICY_IPSEC*/ -#endif /*IPSEC*/ -#if defined(IP_FORCE_OUT_IFP) && TARGET_OS_EMBEDDED - "B:" -#endif /* IP_FORCE_OUT_IFP */ - )) != -1) + while ((ch = getopt_long(argc, argv, + "AaB:b:Cc:DdfG:g:h:I:i:k:K:Ll:M:m:noP:p:QqRrS:s:T:t:vW:z:", + longopts, NULL)) != -1) { switch(ch) { case 'A': @@ -318,12 +331,7 @@ main(int argc, char *const *argv) case 'a': options |= F_AUDIBLE; break; -#if defined(IP_FORCE_OUT_IFP) && TARGET_OS_EMBEDDED case 'B': - (void) snprintf(boundifname, sizeof (boundifname), - "%s", optarg); - break; -#endif /* IP_FORCE_OUT_IFP */ case 'b': boundif = optarg; break; @@ -421,12 +429,31 @@ main(int argc, char *const *argv) } break; case 'k': - how_traffic_class++; - traffic_class = str2svc(optarg); - if (traffic_class == UINT32_MAX) + if (strcasecmp(optarg, "sendmsg") == 0) { + use_sendmsg++; + break; + } + if (strcasecmp(optarg, "recvmsg") == 0) { + use_recvmsg++; + break; + } + traffic_class = str2sotc(optarg, &valid); + if (valid == false) errx(EX_USAGE, "bad traffic class: `%s'", optarg); break; + case 'K': + if (strcasecmp(optarg, "sendmsg") == 0) { + use_sendmsg++; + break; + } + net_service_type = str2netservicetype(optarg, &valid); + if (valid == false) + errx(EX_USAGE, "bad network service type: `%s'", + optarg); + /* suppress default traffic class (-k can still be specified after -K) */ + traffic_class = -1; + break; case 'L': options |= F_NOLOOP; loop = 0; @@ -470,9 +497,9 @@ main(int argc, char *const *argv) case 'o': options |= F_ONCE; break; + case 'P': #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC - case 'P': options |= F_POLICY; if (!strncmp("in", optarg, 2)) policy_in = strdup(optarg); @@ -480,9 +507,9 @@ main(int argc, char *const *argv) policy_out = strdup(optarg); else errx(1, "invalid security policy"); - break; #endif /*IPSEC_POLICY_IPSEC*/ #endif /*IPSEC*/ + break; case 'p': /* fill buffer with user pattern */ options |= F_PINGFILLED; payload = optarg; @@ -548,10 +575,23 @@ main(int argc, char *const *argv) break; case 'z': options |= F_HDRINCL; - ultmp = strtoul(optarg, &ep, 0); - if (*ep || ep == optarg || ultmp > MAXTOS) + tos = str2tos(optarg, &valid); + if (valid == false) errx(EX_USAGE, "invalid TOS: `%s'", optarg); - tos = ultmp; + break; + case 0: + switch (longopt_flag) { + case LOF_CONNECT: + options |= F_CONNECT; + break; + case LOF_PRTIME: + options |= F_PRTIME; + thiszone = gmt2local(0); + break; + default: + break; + } + longopt_flag = 0; break; default: usage(); @@ -620,7 +660,11 @@ main(int argc, char *const *argv) shostname = snamebuf; } if (bind(s, (struct sockaddr *)&sock_in, sizeof sock_in) == -1) +#if (DEBUG || DEVELOPMENT) + options |= F_HDRINCL; +#else err(1, "bind"); +#endif /* DEBUG || DEVELOPMENT */ } bzero(&whereto, sizeof(whereto)); @@ -678,9 +722,6 @@ main(int argc, char *const *argv) errx(EX_USAGE, "-I, -L, -T flags cannot be used with unicast destination"); - if (datalen >= TIMEVAL_LEN) /* can we time transfer */ - timing = 1; - if (!(options & F_PINGFILLED)) for (i = TIMEVAL_LEN; i < MAX(datalen, sweepmax); ++i) *datap++ = i; @@ -699,13 +740,6 @@ main(int argc, char *const *argv) (char *)&ifscope, sizeof (ifscope)) != 0) err(EX_OSERR, "setsockopt(IP_BOUND_IF)"); } -#if defined(IP_FORCE_OUT_IFP) && TARGET_OS_EMBEDDED - else if (boundifname[0] != 0) { - if (setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, boundifname, - sizeof (boundifname)) != 0) - err(EX_OSERR, "setsockopt(IP_FORCE_OUT_IFP)"); - } -#endif /* IP_FORCE_OUT_IFP */ if (nocell) { if (setsockopt(s, IPPROTO_IP, IP_NO_IFT_CELLULAR, (char *)&nocell, sizeof (nocell)) != 0) @@ -717,11 +751,19 @@ main(int argc, char *const *argv) if (options & F_SO_DONTROUTE) (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, sizeof(hold)); - if (how_traffic_class < 2 && traffic_class >= 0) { - (void) setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS, - (void *)&traffic_class, sizeof (traffic_class)); + if (use_sendmsg == 0) { + if (net_service_type != -1) + if (setsockopt(s, SOL_SOCKET, SO_NET_SERVICE_TYPE, + (void *)&net_service_type, sizeof (net_service_type)) != 0) + warn("setsockopt(SO_NET_SERVICE_TYPE"); + if (traffic_class != -1) { + if (setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS, + (void *)&traffic_class, sizeof (traffic_class)) != 0) + warn("setsockopt(SO_TRAFFIC_CLASS"); + + } } - if (how_traffic_class > 0) { + if (use_recvmsg > 0) { int on = 1; (void) setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS, (void *)&on, sizeof (on)); @@ -824,6 +866,12 @@ main(int argc, char *const *argv) err(EX_OSERR, "setsockopt SO_TIMESTAMP"); } #endif + + if ((options & F_CONNECT)) { + if (connect(s, (struct sockaddr *)&whereto, sizeof whereto) == -1) + err(EX_OSERR, "connect"); + } + if (sweepmax) { if (sweepmin >= sweepmax) errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size"); @@ -880,6 +928,16 @@ main(int argc, char *const *argv) (void)printf("PING %s: %d data bytes\n", hostname, datalen); } + /* + * rdar://25829310 + * + * Clear blocked signals inherited from the parent + */ + sigset_t newset; + sigemptyset(&newset); + if (sigprocmask(SIG_SETMASK, &newset, NULL) != 0) + err(EX_OSERR, "sigprocmask(newset)"); + /* * Use sigaction() instead of signal() to get unambiguous semantics, * in particular with SA_RESTART not set. @@ -967,7 +1025,7 @@ main(int argc, char *const *argv) if (n == 1) { struct timeval *tv = NULL; #ifdef SO_TIMESTAMP - struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl; + struct cmsghdr *cmsg; msg.msg_controllen = sizeof(ctrl); #endif @@ -1094,6 +1152,11 @@ pinger(void) CLR(ntransmitted % mx_dup_ck); + if (datalen >= TIMEVAL_LEN) /* can we time transfer */ + timing = 1; + else + timing = 0; + if ((options & F_TIME) || timing) { (void)gettimeofday(&now, NULL); @@ -1120,34 +1183,55 @@ pinger(void) ip->ip_sum = in_cksum((u_short *)outpackhdr, cc); packet = outpackhdr; } - if (how_traffic_class > 1 && traffic_class >= 0) { + if (use_sendmsg > 0) { struct msghdr msg; struct iovec iov; - char *cmbuf[CMSG_SPACE(sizeof(int))]; + char cmbuf[2 * CMSG_SPACE(sizeof(int))]; struct cmsghdr *cm = (struct cmsghdr *)cmbuf; + if ((options & F_CONNECT)) { + msg.msg_name = NULL; + msg.msg_namelen = 0; + } else { msg.msg_name = &whereto; msg.msg_namelen = sizeof(whereto); - + } iov.iov_base = packet; iov.iov_len = cc; msg.msg_iov = &iov; msg.msg_iovlen = 1; - cm->cmsg_len = CMSG_LEN(sizeof(int)); - cm->cmsg_level = SOL_SOCKET; - cm->cmsg_type = SO_TRAFFIC_CLASS; - *(int *)CMSG_DATA(cm) = traffic_class; - msg.msg_control = cm; - msg.msg_controllen = CMSG_SPACE(sizeof(int)); + msg.msg_controllen = 0; + msg.msg_control = NULL; + + if (traffic_class >= 0) { + cm->cmsg_len = CMSG_LEN(sizeof(int)); + cm->cmsg_level = SOL_SOCKET; + cm->cmsg_type = SO_TRAFFIC_CLASS; + *(int *)CMSG_DATA(cm) = traffic_class; + msg.msg_controllen += CMSG_SPACE(sizeof(int)); + cm = (struct cmsghdr *)(((char *)cm) + CMSG_SPACE(sizeof(int))); + } + if (net_service_type >= 0) { + cm->cmsg_len = CMSG_LEN(sizeof(int)); + cm->cmsg_level = SOL_SOCKET; + cm->cmsg_type = SO_NET_SERVICE_TYPE; + msg.msg_controllen += CMSG_SPACE(sizeof(int)); + *(int *)CMSG_DATA(cm) = net_service_type; + } + msg.msg_control = cmbuf; msg.msg_flags = 0; i = sendmsg(s, &msg, 0); } else { + if ((options & F_CONNECT)) { + i = send(s, (char *)packet, cc, 0); + } else { i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto, sizeof(whereto)); } + } if (i < 0 || i != cc) { if (i < 0) { if (options & F_FLOOD && errno == ENOBUFS) { @@ -1267,6 +1351,8 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv, seq_datalen = sweepmin + (seq / snpackets) * sweepincr; seq_sent_len = icmp_len + seq_datalen; } + if (options & F_PRTIME) + pr_currenttime(); (void)printf("%d bytes from %s: icmp_seq=%u", cc, inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), seq); @@ -1353,6 +1439,8 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv, (oip->ip_p == IPPROTO_ICMP) && (oicmp->icmp_type == ICMP_ECHO) && (oicmp->icmp_id == ident))) { + if (options & F_PRTIME) + pr_currenttime(); (void)printf("%d bytes from %s: ", cc, pr_addr(from->sin_addr)); pr_icmph(icp); @@ -1862,14 +1950,16 @@ fill(char *bp, char *patp) } } -uint32_t -str2svc(const char *str) +int +str2sotc(const char *str, bool *valid) { - uint32_t svc; + int sotc = -1; char *endptr; + *valid = true; + if (str == NULL || *str == '\0') - svc = UINT32_MAX; + *valid = false; else if (strcasecmp(str, "BK_SYS") == 0) return SO_TC_BK_SYS; else if (strcasecmp(str, "BK") == 0) @@ -1891,13 +1981,132 @@ str2svc(const char *str) else if (strcasecmp(str, "CTL") == 0) return SO_TC_CTL; else { - svc = strtoul(str, &endptr, 0); + sotc = (int)strtol(str, &endptr, 0); if (*endptr != '\0') - svc = UINT32_MAX; + *valid = false; + } + return (sotc); +} + +int +str2netservicetype(const char *str, bool *valid) +{ + int svc = -1; + char *endptr; + + *valid = true; + + if (str == NULL || *str == '\0') + *valid = false; + else if (strcasecmp(str, "BK") == 0) + return NET_SERVICE_TYPE_BK; + else if (strcasecmp(str, "BE") == 0) + return NET_SERVICE_TYPE_BE; + else if (strcasecmp(str, "VI") == 0) + return NET_SERVICE_TYPE_VI; + else if (strcasecmp(str, "SIG") == 0) + return NET_SERVICE_TYPE_SIG; + else if (strcasecmp(str, "VO") == 0) + return NET_SERVICE_TYPE_VO; + else if (strcasecmp(str, "RV") == 0) + return NET_SERVICE_TYPE_RV; + else if (strcasecmp(str, "AV") == 0) + return NET_SERVICE_TYPE_AV; + else if (strcasecmp(str, "OAM") == 0) + return NET_SERVICE_TYPE_OAM; + else if (strcasecmp(str, "RD") == 0) + return NET_SERVICE_TYPE_RD; + else { + svc = (int)strtol(str, &endptr, 0); + if (*endptr != '\0') + *valid = false; } return (svc); } +u_int8_t +str2tos(const char *str, bool *valid) +{ + u_int8_t dscp = -1; + char *endptr; + + *valid = true; + + if (str == NULL || *str == '\0') + *valid = false; + else if (strcasecmp(str, "DF") == 0) + dscp = _DSCP_DF; + else if (strcasecmp(str, "EF") == 0) + dscp = _DSCP_EF; + else if (strcasecmp(str, "VA") == 0) + dscp = _DSCP_VA; + + else if (strcasecmp(str, "CS0") == 0) + dscp = _DSCP_CS0; + else if (strcasecmp(str, "CS1") == 0) + dscp = _DSCP_CS1; + else if (strcasecmp(str, "CS2") == 0) + dscp = _DSCP_CS2; + else if (strcasecmp(str, "CS3") == 0) + dscp = _DSCP_CS3; + else if (strcasecmp(str, "CS4") == 0) + dscp = _DSCP_CS4; + else if (strcasecmp(str, "CS5") == 0) + dscp = _DSCP_CS5; + else if (strcasecmp(str, "CS6") == 0) + dscp = _DSCP_CS6; + else if (strcasecmp(str, "CS7") == 0) + dscp = _DSCP_CS7; + + else if (strcasecmp(str, "AF11") == 0) + dscp = _DSCP_AF11; + else if (strcasecmp(str, "AF12") == 0) + dscp = _DSCP_AF12; + else if (strcasecmp(str, "AF13") == 0) + dscp = _DSCP_AF13; + else if (strcasecmp(str, "AF21") == 0) + dscp = _DSCP_AF21; + else if (strcasecmp(str, "AF22") == 0) + dscp = _DSCP_AF22; + else if (strcasecmp(str, "AF23") == 0) + dscp = _DSCP_AF23; + else if (strcasecmp(str, "AF31") == 0) + dscp = _DSCP_AF31; + else if (strcasecmp(str, "AF32") == 0) + dscp = _DSCP_AF32; + else if (strcasecmp(str, "AF33") == 0) + dscp = _DSCP_AF33; + else if (strcasecmp(str, "AF41") == 0) + dscp = _DSCP_AF41; + else if (strcasecmp(str, "AF42") == 0) + dscp = _DSCP_AF42; + else if (strcasecmp(str, "AF43") == 0) + dscp = _DSCP_AF43; + + else { + unsigned long val = strtoul(str, &endptr, 0); + if (*endptr != '\0' || val > 255) + *valid = false; + else + return ((u_int8_t)val); + } + /* DSCP occupies the 6 upper bits of the TOS field */ + return (dscp << 2); +} + +void +pr_currenttime(void) +{ + int s; + struct timeval tv; + + gettimeofday(&tv, NULL); + + s = (tv.tv_sec + thiszone) % 86400; + printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60, + (u_int32_t)tv.tv_usec); +} + #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) #define SECOPT " [-P policy]" #else @@ -1908,14 +2117,20 @@ usage(void) { (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", -"usage: ping [-AaDdfnoQqRrv] [-b boundif] [-c count] [-G sweepmaxsize]", -" [-g sweepminsize] [-h sweepincrsize] [-i wait] [−k trafficclass]", +"usage: ping [-AaDdfnoQqRrv] [-c count] [-G sweepmaxsize]", +" [-g sweepminsize] [-h sweepincrsize] [-i wait]", " [-l preload] [-M mask | time] [-m ttl]" SECOPT " [-p pattern]", -" [-S src_addr] [-s packetsize] [-t timeout][-W waittime] [-z tos]", -" host", -" ping [-AaDdfLnoQqRrv] [-b boundif] [-c count] [-I iface] [-i wait]", -" [−k trafficclass] [-l preload] [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]", +" [-S src_addr] [-s packetsize] [-t timeout][-W waittime]", +" [-z tos] host", +" ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait]", +" [-l preload] [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]", " [-s packetsize] [-T ttl] [-t timeout] [-W waittime]", " [-z tos] mcast-group"); + (void)fprintf(stderr, "Apple specific options (to be specified before mcast-group or host like all options)\n"); + (void)fprintf(stderr, " -b boundif # bind the socket to the interface\n"); + (void)fprintf(stderr, " -k traffic_class # set traffic class socket option\n"); + (void)fprintf(stderr, " -K net_service_type # set traffic class socket options\n"); + (void)fprintf(stderr, " -apple-connect # call connect(2) in the socket\n"); + (void)fprintf(stderr, " -apple-time # display current time\n"); exit(EX_USAGE); } diff --git a/ping6.tproj/ping6.8 b/ping6.tproj/ping6.8 index 716668c..e19b066 100644 --- a/ping6.tproj/ping6.8 +++ b/ping6.tproj/ping6.8 @@ -79,9 +79,15 @@ packets to network hosts .Op Fl c Ar count .Ek .Bk -words +.Op Fl G Ar sweepmaxsize[,sweepminsize[,sweepincrsize]] +.Ek +.Bk -words .Op Fl g Ar gateway .Ek .Bk -words +.Op Fl G Ar sweep +.Ek +.Bk -words .Op Fl h Ar hoplimit .Ek .Bk -words @@ -94,6 +100,9 @@ packets to network hosts .Op Fl k Ar trafficclass .Ek .Bk -words +.Op Fl K Ar netservicetype +.Ek +.Bk -words .Op Fl l Ar preload .Ek .Bk -words @@ -113,6 +122,12 @@ packets to network hosts .Op Fl z Ar tclass .Ek .Bk -words +.Op Fl Fl apple-connect +.Ek +.Bk -words +.Op Fl Fl apple-print +.Ek +.Bk -words .Op Ar hops ... .Ek .Bk -words @@ -169,6 +184,7 @@ This is an experimental option. Set socket buffer size. .It Fl B Ar boundif Bind the socket to interface +This option is an Apple addition. .Ar boundif for sending. .It Fl C @@ -179,6 +195,10 @@ Stop after sending .Ar count .Tn ECHO_RESPONSE packets. +If this option is specified in conjunction with ping sweeps, +each sweep will consist of +.Ar count +packets. .It Fl D Disable IPv6 fragmentation. .It Fl d @@ -204,6 +224,18 @@ Only the super-user may use this option. .Bf -emphasis This can be very hard on a network and should be used with caution. .Ef +.It Fl G Ar sweepmaxsize[,sweepminsize[,sweepincrsize]] +.Ar sweepmaxsize +specifies the maximum size of the payload when sending sweeping +pings and is required for sweeps. +.Ar sweepminsize +specifies the size of the payload to start with when sending +sweeping pings -- the default value is 0. +.Ar sweepincrsize +specifies the number of bytes to increment the size of the payload +after each sweep when sending sweeping pings -- the default value +is 1. +This option is an Apple addition. .It Fl g Ar gateway Specifies to use .Ar gateway @@ -231,13 +263,19 @@ values less than 0.1 second. This option is incompatible with the .Fl f option. -.It Fl k Ar trafficlass +.It Fl k Ar trafficclass Specifies the traffic class to use for sending ICMPv6 packets. The supported traffic classes are BK_SYS, BK, BE, RD, OAM, AV, RV, VI, VO and CTL. By default .Nm uses the control traffic class (CTL). +This option is an Apple addition. +.It Fl K Ar netservicetype +Specifies the network service type to use for sending ICMPv6 packets. +The supported network service type are BK_SYS, BK, BE, RV, AV, RD, OAM, VI, SIG and VO. +Note this overrides the default traffic class (-k can still be specified after -K to use both). +This option is an Apple addition. .It Fl l Ar preload If .Ar preload @@ -354,6 +392,12 @@ has no effect if is specified. .It Fl z Ar tclass Use the specified traffic class. +.It Fl Fl apple-connect +Connects the socket to the destination address. +This option is an Apple addition. +.It Fl Fl apple-print +Prints the time a packet was received. +This option is an Apple addition. .It Ar hops IPv6 addresses for intermediate nodes, which will be put into type 0 routing header. diff --git a/ping6.tproj/ping6.c b/ping6.tproj/ping6.c index 90da21a..c5b0785 100644 --- a/ping6.tproj/ping6.c +++ b/ping6.tproj/ping6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2013 Apple Inc. All rights reserved. + * Copyright (c) 2002-2016 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -143,6 +143,7 @@ __unused static const char copyright[] = #include #include #include +#include #include #include #include @@ -151,6 +152,7 @@ __unused static const char copyright[] = #include #endif #include +#include #ifdef IPSEC #include @@ -189,6 +191,7 @@ struct tv32 { #define F_QUIET 0x0010 #define F_RROUTE 0x0020 #define F_SO_DEBUG 0x0040 +#define F_PRTIME 0x0080 #define F_VERBOSE 0x0100 #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC @@ -211,9 +214,23 @@ struct tv32 { #define F_AUDIBLE 0x400000 #define F_MISSED 0x800000 #define F_DONTFRAG 0x1000000 +#define F_SWEEP 0x2000000 +#define F_CONNECT 0x4000000 #define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES) u_int options; +static int longopt_flag = 0; + +#define LOF_CONNECT 0x01 +#define LOF_PRTIME 0x02 + +static const struct option longopts[] = { + { "apple-connect", no_argument, &longopt_flag, LOF_CONNECT }, + { "apple-time", no_argument, &longopt_flag, LOF_PRTIME }, + { NULL, 0, NULL, 0 } +}; + + #define IN6LEN sizeof(struct in6_addr) #define SA6LEN sizeof(struct sockaddr_in6) #define DUMMY_PORT 10101 @@ -264,6 +281,11 @@ long nreceived; /* # of packets we got back */ long nrepeats; /* number of duplicates */ long ntransmitted; /* sequence # for outbound packets = #sent */ struct timeval interval = {1, 0}; /* interval between packets */ +long snpackets = 0; /* max packets to transmit in one sweep */ +long sntransmitted = 0; /* # of packets we sent in this sweep */ +int sweepmax = 0; /* max value of payload in sweep */ +int sweepmin = 0; /* start value of payload in sweep */ +int sweepincr = 1; /* payload increment in sweep */ /* timing */ int timing; /* flag to do timing */ @@ -277,7 +299,7 @@ u_short naflags; /* for ancillary data(advanced API) */ struct msghdr smsghdr; -struct iovec smsgiov; +struct iovec smsgiov[2]; char *scmsg = NULL; volatile sig_atomic_t seenalrm; @@ -288,8 +310,14 @@ volatile sig_atomic_t seeninfo; int rcvtclass = 0; -int how_so_traffic_class = 0; +int use_sendmsg = 0; +int use_recvmsg = 0; int so_traffic_class = SO_TC_CTL; /* use control class, by default */ +int net_service_type = -1; + +int32_t thiszone; /* seconds offset from gmt to local time */ +extern int32_t gmt2local(time_t); +static void pr_currenttime(void); int main(int, char *[]); void fill(char *, char *); @@ -322,7 +350,9 @@ void summary(void); void tvsub(struct timeval *, struct timeval *); int setpolicy(int, char *); char *nigroup(char *); -static uint32_t str2svc(const char *); +static int str2sotc(const char *, bool *); +static int str2netservicetype(const char *, bool *); +static u_int8_t str2tclass(const char *, bool *); void usage(void); int @@ -365,6 +395,8 @@ main(int argc, char *argv[]) #endif /* T_CLASS value -1 means default, so -2 means do not bother */ int tclass = -2; + bool valid; + struct timeval intvl; /* just to be sure */ memset(&smsghdr, 0, sizeof(smsghdr)); @@ -381,8 +413,9 @@ main(int argc, char *argv[]) #define ADDOPTS "AE" #endif /*IPSEC_POLICY_IPSEC*/ #endif - while ((ch = getopt(argc, argv, - "a:b:B:Cc:DdfHg:h:I:i:k:l:mnNop:qrRS:s:tvwWz:" ADDOPTS)) != -1) { + while ((ch = getopt_long(argc, argv, + "a:b:B:Cc:DdfHG:g:h:I:i:k:K:l:mnNop:qrRS:s:tvwWz:" ADDOPTS, + longopts, NULL)) != -1) { #undef ADDOPTS switch (ch) { case 'a': @@ -471,6 +504,66 @@ main(int argc, char *argv[]) case 'g': gateway = optarg; break; + case 'G': { + char *ptr ; + char *tofree; + unsigned long ultmp; + + tofree = strdup(optarg); + if (tofree == NULL) + errx(1, "### strdup() failed"); + ptr = tofree; + do { + char *str; + char *ep; + + if ((str = strsep(&ptr, ",")) == NULL) + errx(1, "-G requires maximum packet size"); + ultmp = strtoul(str, &ep, 0); + if (*ep || ep == optarg) + errx(EX_USAGE, "option -G invalid maximum packet size: `%s'", + str); + options |= F_SWEEP; + sweepmax = ultmp; + if (sweepmax < 1 || sweepmax > MAXDATALEN) { + errx(1, + "-G invalid maximum packet size, needs to be between 1 and %d", + MAXDATALEN); + } + + if ((str = strsep(&ptr, ",")) == NULL) + break; + if (*str != 0) { + ultmp = strtoul(str, &ep, 0); + if (*ep || ep == optarg) + errx(EX_USAGE, "option -G invalid minimum packet size: `%s'", + str); + sweepmin = ultmp; + if (sweepmin < 0 || sweepmin > MAXDATALEN) { + errx(1, + "-G invalid minimum packet size, needs to be between 0 and %d", + MAXDATALEN); + } + } + + if ((str = strsep(&ptr, ",")) == NULL) + break; + if (*str == 0) + break; + ultmp = strtoul(str, &ep, 0); + if (*ep || ep == optarg) + errx(EX_USAGE, "option -G invalid sweep increment size: `%s'", + str); + sweepincr = ultmp; + if (sweepincr < 1 || sweepincr > MAXDATALEN) { + errx(1, + "-G invalid sweep increment size, needs to be between 1 and %d", + MAXDATALEN); + } + } while (0); + free(tofree); + break; + } case 'H': options |= F_HOSTNAME; break; @@ -510,13 +603,31 @@ main(int argc, char *argv[]) options |= F_INTERVAL; break; case 'k': - how_so_traffic_class++; - so_traffic_class = str2svc(optarg); - if (so_traffic_class == UINT32_MAX) + if (strcasecmp(optarg, "sendmsg") == 0) { + use_sendmsg++; + break; + } + if (strcasecmp(optarg, "recvmsg") == 0) { + use_recvmsg++; + break; + } + so_traffic_class = str2sotc(optarg, &valid); + if (valid == false) errx(EX_USAGE, "bad traffic class: `%s'", optarg); break; - + case 'K': + if (strcasecmp(optarg, "sendmsg") == 0) { + use_sendmsg++; + break; + } + net_service_type = str2netservicetype(optarg, &valid); + if (valid == false) + errx(EX_USAGE, "bad network service type: `%s'", + optarg); + /* suppress default traffic class (-k can still be specified after -K) */ + so_traffic_class = -1; + break; case 'l': if (getuid()) { errno = EPERM; @@ -546,7 +657,7 @@ main(int argc, char *argv[]) case 'p': /* fill buffer with user pattern */ options |= F_PINGFILLED; fill((char *)datap, optarg); - break; + break; case 'q': options |= F_QUIET; break; @@ -604,13 +715,9 @@ main(int argc, char *argv[]) options |= F_FQDNOLD; break; case 'z': - tclass = (int)strtol(optarg, &e, 10); - if (tclass < -1 || *optarg == '\0' || *e != '\0') + tclass = str2tclass(optarg, &valid); + if (valid == false) errx(1, "illegal TOS value -- %s", optarg); - if (tclass > MAXTOS) - errx(1, - "TOS value too large, maximum is %d", - MAXTOS); rcvtclass = 1; break; #ifdef IPSEC @@ -635,6 +742,20 @@ main(int argc, char *argv[]) break; #endif /*IPSEC_POLICY_IPSEC*/ #endif /*IPSEC*/ + case 0: + switch (longopt_flag) { + case LOF_CONNECT: + options |= F_CONNECT; + break; + case LOF_PRTIME: + options |= F_PRTIME; + thiszone = gmt2local(0); + break; + default: + break; + } + longopt_flag = 0; + break; default: usage(); /*NOTREACHED*/ @@ -644,6 +765,12 @@ main(int argc, char *argv[]) if (boundif != NULL && (ifscope = if_nametoindex(boundif)) == 0) errx(1, "bad interface name"); + if ((options & F_SWEEP) && !sweepmax) + errx(EX_USAGE, "Maximum sweep size must be specified"); + + if ((options & F_SWEEP) && (options & F_NOUSERDATA)) + errx(EX_USAGE, "Option -G incompatible with -t, -w and -W"); + argc -= optind; argv += optind; @@ -787,17 +914,32 @@ main(int argc, char *argv[]) if ((options & F_FLOOD) && (options & F_INTERVAL)) errx(1, "-f and -i incompatible options"); - if ((options & F_NOUSERDATA) == 0) { - if (datalen >= sizeof(struct tv32)) { - /* we can time transfer */ - timing = 1; + if ((options & F_CONNECT)) { + if (connect(s, (struct sockaddr *)&dst, sizeof(dst)) == -1) + err(EX_OSERR, "connect"); + } + + if (sweepmax) { + if (sweepmin >= sweepmax) + errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size"); + + if (datalen != DEFDATALEN) + errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive"); + + if (npackets > 0) { + snpackets = npackets; + npackets = 0; } else - timing = 0; + snpackets = 1; + datalen = sweepmin; + } + + if ((options & F_NOUSERDATA) == 0) { /* in F_VERBOSE case, we may get non-echoreply packets*/ if (options & F_VERBOSE) - packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; + packlen = MAX(2048, sweepmax) + IP6LEN + ICMP6ECHOLEN + EXTRA; else - packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA; + packlen = MAX(datalen, sweepmax) + IP6LEN + ICMP6ECHOLEN + EXTRA; } else { /* suppress timing for node information query */ timing = 0; @@ -805,10 +947,10 @@ main(int argc, char *argv[]) packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; } - if (!(packet = (u_char *)malloc((u_int)packlen))) + if (!(packet = (u_char *)malloc((u_int)MAX(datalen, sweepmax)))) err(1, "Unable to allocate packet"); if (!(options & F_PINGFILLED)) - for (i = ICMP6ECHOLEN; i < packlen; ++i) + for (i = ICMP6ECHOLEN; i < MAX(datalen, sweepmax); ++i) *datap++ = i; ident = getpid() & 0xFFFF; @@ -959,17 +1101,29 @@ main(int argc, char *argv[]) if (tclass != -2) ip6optlen += CMSG_SPACE(sizeof(int)); - if (how_so_traffic_class < 2 && so_traffic_class >= 0) { - (void) setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS, - (void *)&so_traffic_class, sizeof (so_traffic_class)); + if (use_sendmsg == 0) { + if (net_service_type != -1) + if (setsockopt(s, SOL_SOCKET, SO_NET_SERVICE_TYPE, + (void *)&net_service_type, sizeof (net_service_type)) != 0) + warn("setsockopt(SO_NET_SERVICE_TYPE"); + if (so_traffic_class != -1) { + if (setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS, + (void *)&so_traffic_class, sizeof (so_traffic_class)) != 0) + warn("setsockopt(SO_TRAFFIC_CLASS"); + + } + } else { + if (net_service_type != -1) + ip6optlen += CMSG_SPACE(sizeof(int)); + if (so_traffic_class != -1) + ip6optlen += CMSG_SPACE(sizeof(int)); } - if (how_so_traffic_class > 0) { + if (use_recvmsg > 0) { int on = 1; - (void) setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS, - (void *)&on, sizeof (on)); + if (setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS, + (void *)&on, sizeof (on)) != 0) + warn("setsockopt(SO_RECV_TRAFFIC_CLASS"); } - if (how_so_traffic_class > 1) - ip6optlen += CMSG_SPACE(sizeof(int)); /* set IP6 packet options */ if (ip6optlen) { @@ -1082,13 +1236,21 @@ main(int argc, char *argv[]) scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); } - if (how_so_traffic_class > 1 && so_traffic_class >= 0) { - scmsgp->cmsg_len = CMSG_LEN(sizeof(int)); - scmsgp->cmsg_level = SOL_SOCKET; - scmsgp->cmsg_type = SO_TRAFFIC_CLASS; - *(int *)(CMSG_DATA(scmsgp)) = so_traffic_class; + if (use_sendmsg != 0) { + if (so_traffic_class != -1) { + scmsgp->cmsg_len = CMSG_LEN(sizeof(int)); + scmsgp->cmsg_level = SOL_SOCKET; + scmsgp->cmsg_type = SO_TRAFFIC_CLASS; + *(int *)(CMSG_DATA(scmsgp)) = so_traffic_class; - scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); + scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); + } + if (net_service_type != -1) { + scmsgp->cmsg_len = CMSG_LEN(sizeof(int)); + scmsgp->cmsg_level = SOL_SOCKET; + scmsgp->cmsg_type = SO_NET_SERVICE_TYPE; + *(int *)(CMSG_DATA(scmsgp)) = net_service_type; + } } if (!(options & F_SRCADDR)) { /* @@ -1156,7 +1318,7 @@ main(int argc, char *argv[]) #if defined(SO_SNDBUF) && defined(SO_RCVBUF) if (sockbufsize) { - if (datalen > sockbufsize) + if (MAX(datalen, sweepmax) > sockbufsize) warnx("you need -b to increase socket buffer size"); if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize, sizeof(sockbufsize)) < 0) @@ -1166,7 +1328,7 @@ main(int argc, char *argv[]) err(1, "setsockopt(SO_RCVBUF)"); } else { - if (datalen > 8 * 1024) /*XXX*/ + if (MAX(datalen, sweepmax) > 8 * 1024) /*XXX*/ warnx("you need -b to increase socket buffer size"); /* * When pinging the broadcast address, you can get a lot of @@ -1203,21 +1365,42 @@ main(int argc, char *argv[]) optval, sizeof(optval)); /* XXX err? */ #endif - printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()), - (unsigned long)(pingerlen() - 8)); + if (sweepmax) + printf("PING6(40+8+[%lu...%lu] bytes) ", + (unsigned long)(sweepmin), + (unsigned long)(sweepmax)); + else + printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()), + (unsigned long)(pingerlen() - 8)); printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src))); printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst))); while (preload--) /* Fire off them quickies. */ (void)pinger(); + /* + * rdar://25829310 + * + * Clear blocked signals inherited from the parent + */ + sigset_t newset; + sigemptyset(&newset); + if (sigprocmask(SIG_SETMASK, &newset, NULL) != 0) + err(EX_OSERR, "sigprocmask(newset)"); + + seenalrm = seenint = 0; +#ifdef SIGINFO + seeninfo = 0; +#endif + (void)signal(SIGINT, onsignal); #ifdef SIGINFO (void)signal(SIGINFO, onsignal); #endif if ((options & F_FLOOD) == 0) { - (void)signal(SIGALRM, onsignal); + if (signal(SIGALRM, onsignal) == SIG_ERR) + warn("signal(SIGALRM)"); itimer.it_interval = interval; itimer.it_value = interval; (void)setitimer(ITIMER_REAL, &itimer, NULL); @@ -1225,17 +1408,20 @@ main(int argc, char *argv[]) retransmit(); } + if (options & F_FLOOD) { + intvl.tv_sec = 0; + intvl.tv_usec = 10000; + } else { + intvl.tv_sec = interval.tv_sec; + intvl.tv_usec = interval.tv_usec; + } + #ifndef HAVE_POLL_H fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask); if ((fdmaskp = malloc(fdmasks)) == NULL) err(1, "malloc"); #endif - seenalrm = seenint = 0; -#ifdef SIGINFO - seeninfo = 0; -#endif - /* For control (ancillary) data received from recvmsg() */ cm = (struct cmsghdr *)malloc(CONTROLLEN); if (cm == NULL) @@ -1247,28 +1433,32 @@ main(int argc, char *argv[]) /* signal handling */ if (seenalrm) { + seenalrm = 0; /* last packet sent, timeout reached? */ if (npackets && ntransmitted >= npackets) break; + /* sweep done ? */ + if (sweepmax && datalen > sweepmax) + break; retransmit(); - seenalrm = 0; continue; } if (seenint) { - onint(SIGINT); seenint = 0; + onint(SIGINT); continue; } #ifdef SIGINFO if (seeninfo) { - summary(); seeninfo = 0; + summary(); continue; } #endif if (options & F_FLOOD) { - (void)pinger(); + if (pinger() != 0) + break; #ifdef HAVE_POLL_H timeout = 10; #else @@ -1302,9 +1492,9 @@ main(int argc, char *argv[]) sleep(1); } continue; - } else if (cc == 0) + } else if (cc == 0) { continue; - + } m.msg_name = (caddr_t)&from; m.msg_namelen = sizeof(from); memset(&iov, 0, sizeof(iov)); @@ -1378,7 +1568,8 @@ main(int argc, char *argv[]) void onsignal(int sig) { - + fflush(stdout); + switch (sig) { case SIGALRM: seenalrm++; @@ -1403,9 +1594,9 @@ retransmit(void) { struct itimerval itimer; - if (pinger() == 0) + if (pinger() == 0) { return; - + } /* * If we're not transmitting any more packets, change the timer * to wait two round-trip times if we've received any packets or @@ -1457,7 +1648,6 @@ int pinger(void) { struct icmp6_hdr *icp; - struct iovec iov[2]; int i, cc; struct icmp6_nodeinfo *nip; int seq; @@ -1465,6 +1655,13 @@ pinger(void) if (npackets && ntransmitted >= npackets) return(-1); /* no more transmission */ + if (sweepmax && sntransmitted == snpackets) { + datalen += sweepincr; + if (datalen > sweepmax) + return(-1); /* no more transmission */ + sntransmitted = 0; + } + icp = (struct icmp6_hdr *)outpack; nip = (struct icmp6_nodeinfo *)outpack; memset(icp, 0, sizeof(*icp)); @@ -1530,6 +1727,11 @@ pinger(void) icp->icmp6_code = 0; icp->icmp6_id = htons(ident); icp->icmp6_seq = ntohs(seq); + if (datalen >= sizeof(struct tv32)) { + /* we can time transfer */ + timing = 1; + } else + timing = 0; if (timing) { struct timeval tv; struct tv32 *tv32; @@ -1546,12 +1748,17 @@ pinger(void) errx(1, "internal error; length mismatch"); #endif + if ((options & F_CONNECT)) { + smsghdr.msg_name = NULL; + smsghdr.msg_namelen = 0; + } else { smsghdr.msg_name = (caddr_t)&dst; smsghdr.msg_namelen = sizeof(dst); - memset(&iov, 0, sizeof(iov)); - iov[0].iov_base = (caddr_t)outpack; - iov[0].iov_len = cc; - smsghdr.msg_iov = iov; + } + memset(&smsgiov, 0, sizeof(smsgiov)); + smsgiov[0].iov_base = (caddr_t)outpack; + smsgiov[0].iov_len = cc; + smsghdr.msg_iov = smsgiov; smsghdr.msg_iovlen = 1; i = sendmsg(s, &smsghdr, 0); @@ -1562,6 +1769,7 @@ pinger(void) (void)printf("ping6: wrote %s %d chars, ret=%d\n", hostname, cc, i); } + sntransmitted++; if (!(options & F_QUIET) && options & F_FLOOD) (void)write(STDOUT_FILENO, &DOT, 1); @@ -1593,7 +1801,7 @@ dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf, size_t bufsiz) /*base for compressed name*/ { - int i; + int i = 0; const u_char *cp; char cresult[NS_MAXDNAME + 1]; const u_char *comp; @@ -1715,7 +1923,7 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr) return; } - if (how_so_traffic_class > 0) + if (use_recvmsg > 0) sotc = get_so_traffic_class(mhdr); if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) { @@ -1753,6 +1961,8 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr) else { if (options & F_AUDIBLE) (void)write(STDOUT_FILENO, &BBELL, 1); + if (options & F_PRTIME) + pr_currenttime(); (void)printf("%d bytes from %s, icmp_seq=%u", cc, pr_addr(from, fromlen), seq); (void)printf(" hlim=%d", hoplim); @@ -1796,15 +2006,15 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr) if (TST(seq % mx_dup_ck)) { ++nrepeats; --nreceived; - dupflag = 1; } else { SET(seq % mx_dup_ck); - dupflag = 0; } if (options & F_QUIET) return; + if (options & F_PRTIME) + pr_currenttime(); (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); switch (ntohs(ni->ni_code)) { @@ -1941,6 +2151,8 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr) /* We've got something other than an ECHOREPLY */ if (!(options & F_VERBOSE)) return; + if (options & F_PRTIME) + pr_currenttime(); (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); pr_icmph(icp, end); } @@ -1961,7 +2173,6 @@ pr_exthdrs(struct msghdr *mhdr) void *bufp; struct cmsghdr *cm; - bufsize = 0; bufp = mhdr->msg_control; for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { @@ -1998,7 +2209,7 @@ pr_ip6opt(void *extbuf, size_t bufsize) struct ip6_hbh *ext; int currentlen; u_int8_t type; - socklen_t extlen, len, origextlen; + socklen_t extlen, len; void *databuf; size_t offset; u_int16_t value2; @@ -2014,7 +2225,6 @@ pr_ip6opt(void *extbuf, size_t bufsize) * subtract the size of a cmsg structure from the buffer size. */ if (bufsize < (extlen + CMSG_SPACE(0))) { - origextlen = extlen; extlen = bufsize - CMSG_SPACE(0); warnx("options truncated, showing only %u (total=%u)", (unsigned int)(extlen / 8 - 1), @@ -2034,14 +2244,14 @@ pr_ip6opt(void *extbuf, size_t bufsize) */ case IP6OPT_JUMBO: offset = 0; - offset = inet6_opt_get_val(databuf, offset, + (void) inet6_opt_get_val(databuf, offset, &value4, sizeof(value4)); printf(" Jumbo Payload Opt: Length %u\n", (u_int32_t)ntohl(value4)); break; case IP6OPT_ROUTER_ALERT: offset = 0; - offset = inet6_opt_get_val(databuf, offset, + (void)inet6_opt_get_val(databuf, offset, &value2, sizeof(value2)); printf(" Router Alert Opt: Type %u\n", ntohs(value2)); @@ -2187,7 +2397,7 @@ pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen) struct cbit { u_int16_t words; /*32bit count*/ u_int16_t skip; - } cbit; + } cbit = { 0, 0 }; #define MAXQTYPES (1 << 16) size_t off; int b; @@ -2995,14 +3205,16 @@ nigroup(char *name) return strdup(hbuf); } -uint32_t -str2svc(const char *str) +int +str2sotc(const char *str, bool *valid) { - uint32_t svc; + int sotc = -1; char *endptr; + *valid = true; + if (str == NULL || *str == '\0') - svc = UINT32_MAX; + *valid = false; else if (strcasecmp(str, "BK_SYS") == 0) return SO_TC_BK_SYS; else if (strcasecmp(str, "BK") == 0) @@ -3024,13 +3236,132 @@ str2svc(const char *str) else if (strcasecmp(str, "CTL") == 0) return SO_TC_CTL; else { - svc = strtoul(str, &endptr, 0); + sotc = (int)strtol(str, &endptr, 0); if (*endptr != '\0') - svc = UINT32_MAX; + *valid = false; + } + return (sotc); +} + +int +str2netservicetype(const char *str, bool *valid) +{ + int svc = -1; + char *endptr; + + *valid = true; + + if (str == NULL || *str == '\0') + *valid = false; + else if (strcasecmp(str, "BK") == 0) + return NET_SERVICE_TYPE_BK; + else if (strcasecmp(str, "BE") == 0) + return NET_SERVICE_TYPE_BE; + else if (strcasecmp(str, "VI") == 0) + return NET_SERVICE_TYPE_VI; + else if (strcasecmp(str, "SIG") == 0) + return NET_SERVICE_TYPE_SIG; + else if (strcasecmp(str, "VO") == 0) + return NET_SERVICE_TYPE_VO; + else if (strcasecmp(str, "RV") == 0) + return NET_SERVICE_TYPE_RV; + else if (strcasecmp(str, "AV") == 0) + return NET_SERVICE_TYPE_AV; + else if (strcasecmp(str, "OAM") == 0) + return NET_SERVICE_TYPE_OAM; + else if (strcasecmp(str, "RD") == 0) + return NET_SERVICE_TYPE_RD; + else { + svc = (int)strtol(str, &endptr, 0); + if (*endptr != '\0') + *valid = false; } return (svc); } +u_int8_t +str2tclass(const char *str, bool *valid) +{ + u_int8_t dscp = -1; + char *endptr; + + *valid = true; + + if (str == NULL || *str == '\0') + *valid = false; + else if (strcasecmp(str, "DF") == 0) + dscp = _DSCP_DF; + else if (strcasecmp(str, "EF") == 0) + dscp = _DSCP_EF; + else if (strcasecmp(str, "VA") == 0) + dscp = _DSCP_VA; + + else if (strcasecmp(str, "CS0") == 0) + dscp = _DSCP_CS0; + else if (strcasecmp(str, "CS1") == 0) + dscp = _DSCP_CS1; + else if (strcasecmp(str, "CS2") == 0) + dscp = _DSCP_CS2; + else if (strcasecmp(str, "CS3") == 0) + dscp = _DSCP_CS3; + else if (strcasecmp(str, "CS4") == 0) + dscp = _DSCP_CS4; + else if (strcasecmp(str, "CS5") == 0) + dscp = _DSCP_CS5; + else if (strcasecmp(str, "CS6") == 0) + dscp = _DSCP_CS6; + else if (strcasecmp(str, "CS7") == 0) + dscp = _DSCP_CS7; + + else if (strcasecmp(str, "AF11") == 0) + dscp = _DSCP_AF11; + else if (strcasecmp(str, "AF12") == 0) + dscp = _DSCP_AF12; + else if (strcasecmp(str, "AF13") == 0) + dscp = _DSCP_AF13; + else if (strcasecmp(str, "AF21") == 0) + dscp = _DSCP_AF21; + else if (strcasecmp(str, "AF22") == 0) + dscp = _DSCP_AF22; + else if (strcasecmp(str, "AF23") == 0) + dscp = _DSCP_AF23; + else if (strcasecmp(str, "AF31") == 0) + dscp = _DSCP_AF31; + else if (strcasecmp(str, "AF32") == 0) + dscp = _DSCP_AF32; + else if (strcasecmp(str, "AF33") == 0) + dscp = _DSCP_AF33; + else if (strcasecmp(str, "AF41") == 0) + dscp = _DSCP_AF41; + else if (strcasecmp(str, "AF42") == 0) + dscp = _DSCP_AF42; + else if (strcasecmp(str, "AF43") == 0) + dscp = _DSCP_AF43; + + else { + unsigned long val = strtoul(str, &endptr, 0); + if (*endptr != '\0' || val > 255) + *valid = false; + else + return ((u_int8_t)val); + } + /* DSCP occupies the 6 upper bits of the traffic class field */ + return (dscp << 2); +} + +void +pr_currenttime(void) +{ + int s; + struct timeval tv; + + gettimeofday(&tv, NULL); + + s = (tv.tv_sec + thiszone) % 86400; + printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60, + (u_int32_t)tv.tv_usec); +} + void usage(void) { @@ -3048,13 +3379,21 @@ usage(void) "m" #endif "nNoqrRtvwW] " - "[-a addrtype] [-b bufsiz] [-B boundif] [-c count]\n" + "[-a addrtype] [-b bufsiz] [-c count]\n" " [-g gateway] [-h hoplimit] [-I interface] [-i wait] [-l preload]" #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) " [-P policy]" #endif "\n" " [-p pattern] [-S sourceaddr] [-s packetsize] [-z tclass] " + "[-k traffic_class] [-K net_service_type] " "[hops ...] host\n"); + (void)fprintf(stderr, "Apple specific options (to be specified before hops or host like all options)\n"); + (void)fprintf(stderr, " -b boundif # bind the socket to the interface\n"); + (void)fprintf(stderr, " -k traffic_class # set traffic class socket option\n"); + (void)fprintf(stderr, " -K net_service_type # set traffic class socket options\n"); + (void)fprintf(stderr, " -apple-connect # call connect(2) in the socket\n"); + (void)fprintf(stderr, " -apple-time # display current time\n"); + (void)fprintf(stderr, " -apple-progress # show progress for debugging\n"); exit(1); } diff --git a/pktmnglr/packet_mangler.c b/pktmnglr/packet_mangler.c index fab5ce9..8ce0f8f 100644 --- a/pktmnglr/packet_mangler.c +++ b/pktmnglr/packet_mangler.c @@ -145,7 +145,7 @@ main(int argc, char * const argv[]) { exit(0); } - while ((ch = getopt(argc, argv, "hf:l:r:t:p:m:M:L:R")) != -1) { + while ((ch = getopt(argc, argv, "hf:l:r:t:p:m:M:L:R:")) != -1) { switch (ch) { case 'h': usage(argv[0]); diff --git a/route.tproj/route.c b/route.tproj/route.c index c2508bd..69ee7e1 100644 --- a/route.tproj/route.c +++ b/route.tproj/route.c @@ -127,6 +127,10 @@ int getaddr(), rtmsg(), x25_makemask(); int prefixlen(); extern char *iso_ntoa(); +static void +inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin, + struct sockaddr_in *sin_mask, in_addr_t bits); + void usage __P((const char *)) __dead2; void @@ -414,71 +418,49 @@ routename(sa) /* * Return the name of the network whose address is given. - * The address is assumed to be that of a net or subnet, not a host. + * The address is assumed to be that of a net, not a host. */ const char * netname(sa) struct sockaddr *sa; { - char *cp = 0; + char *cp = NULL; static char line[MAXHOSTNAMELEN + 1]; - struct netent *np = 0; - in_addr_t net, mask; + struct netent *np = NULL; register in_addr_t i; - int subnetshift; switch (sa->sa_family) { - case AF_INET: - { struct in_addr in; - in = ((struct sockaddr_in *)sa)->sin_addr; - - i = in.s_addr = ntohl(in.s_addr); - if (in.s_addr == 0) - cp = "default"; - else if (!nflag) { - if (IN_CLASSA(i)) { - mask = IN_CLASSA_NET; - subnetshift = 8; - } else if (IN_CLASSB(i)) { - mask = IN_CLASSB_NET; - subnetshift = 8; - } else { - mask = IN_CLASSC_NET; - subnetshift = 4; - } - /* - * If there are more bits than the standard mask - * would suggest, subnets must be in use. - * Guess at the subnet mask, assuming reasonable - * width subnet fields. - */ - while (in.s_addr &~ mask) - mask = mask >> subnetshift; - net = in.s_addr & mask; - while ((mask & 1) == 0) - mask >>= 1, net >>= 1; - np = getnetbyaddr(net, AF_INET); - if (np) - cp = np->n_name; - } - if (cp) - strncpy(line, cp, sizeof(line)); - else if ((in.s_addr & 0xffffff) == 0) - (void) snprintf(line, sizeof(line), "%u", C(in.s_addr >> 24)); - else if ((in.s_addr & 0xffff) == 0) - (void) snprintf(line, sizeof(line), "%u.%u", C(in.s_addr >> 24), - C(in.s_addr >> 16)); - else if ((in.s_addr & 0xff) == 0) - (void) snprintf(line, sizeof(line), "%u.%u.%u", C(in.s_addr >> 24), - C(in.s_addr >> 16), C(in.s_addr >> 8)); - else - (void) snprintf(line, sizeof(line), "%u.%u.%u.%u", C(in.s_addr >> 24), - C(in.s_addr >> 16), C(in.s_addr >> 8), - C(in.s_addr)); - break; - } - + case AF_INET: + { struct in_addr in; + in = ((struct sockaddr_in *)sa)->sin_addr; + + i = in.s_addr = ntohl(in.s_addr); + if (in.s_addr == 0) + cp = "default"; + else if (!nflag) { + np = getnetbyaddr(i, AF_INET); + if (np != NULL) + cp = np->n_name; + } +#define C(x) (unsigned)((x) & 0xff) + if (cp != NULL) + strncpy(line, cp, sizeof(line)); + else if ((in.s_addr & 0xffffff) == 0) + (void) sprintf(line, "%u", C(in.s_addr >> 24)); + else if ((in.s_addr & 0xffff) == 0) + (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), + C(in.s_addr >> 16)); + else if ((in.s_addr & 0xff) == 0) + (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), + C(in.s_addr >> 16), C(in.s_addr >> 8)); + else + (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), + C(in.s_addr >> 16), C(in.s_addr >> 8), + C(in.s_addr)); +#undef C + break; + } #ifdef INET6 case AF_INET6: { @@ -787,49 +769,43 @@ newroute(argc, argv) } } -void -inet_makenetandmask(net, sin, bits) - in_addr_t net, bits; - register struct sockaddr_in *sin; +static void +inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin, + struct sockaddr_in *sin_mask, in_addr_t bits) { - in_addr_t addr, mask = 0; - register char *cp; - + in_addr_t mask = 0; + rtm_addrs |= RTA_NETMASK; - if (bits) { - addr = net; - mask = 0xffffffff << (32 - bits); - } else if (net == 0) - mask = addr = 0; - else if (net < 128) { - addr = net << IN_CLASSA_NSHIFT; - mask = IN_CLASSA_NET; - } else if (net < 65536) { - addr = net << IN_CLASSB_NSHIFT; - mask = IN_CLASSB_NET; - } else if (net < 16777216L) { - addr = net << IN_CLASSC_NSHIFT; - mask = IN_CLASSC_NET; - } else { - addr = net; - if ((addr & IN_CLASSA_HOST) == 0) - mask = IN_CLASSA_NET; - else if ((addr & IN_CLASSB_HOST) == 0) - mask = IN_CLASSB_NET; - else if ((addr & IN_CLASSC_HOST) == 0) - mask = IN_CLASSC_NET; - else - mask = -1; + /* + * MSB of net should be meaningful. 0/0 is exception. + */ + if (net > 0) + while ((net & 0xff000000) == 0) + net <<= 8; + + /* + * If no /xx was specified we must calculate the + * CIDR address. + */ + if ((bits == 0) && (net != 0)) { + u_long i, j; + + for(i = 0, j = 0xff; i < 4; i++) { + if (net & j) { + break; + } + j <<= 8; + } + /* i holds the first non zero bit */ + bits = 32 - (i*8); } - sin->sin_addr.s_addr = htonl(addr); - sin = &so_mask.sin; - sin->sin_addr.s_addr = htonl(mask); - sin->sin_len = 0; - sin->sin_family = 0; - cp = (char *)(&sin->sin_addr + 1); - while (*--cp == 0 && cp > (char *)sin) - ; - sin->sin_len = 1 + cp - (char *)sin; + if (bits != 0) + mask = 0xffffffff << (32 - bits); + + sin->sin_addr.s_addr = htonl(net); + sin_mask->sin_addr.s_addr = htonl(mask); + sin_mask->sin_len = sizeof(struct sockaddr_in); + sin_mask->sin_family = AF_INET; } #ifdef INET6 @@ -1026,17 +1002,18 @@ getaddr(which, s, hpp) q = strchr(s,'/'); if (q && which == RTA_DST) { *q = '\0'; - if ((val = inet_addr(s)) != INADDR_NONE) { + if ((val = inet_network(s)) != INADDR_NONE) { inet_makenetandmask( - ntohl(val), &su->sin, strtoul(q+1, 0, 0)); + val, &su->sin, (struct sockaddr_in *)&so_mask, + strtoul(q+1, 0, 0)); return (0); } *q = '/'; } if ((which != RTA_DST || forcenet == 0) && - (val = inet_addr(s)) != INADDR_NONE) { - su->sin.sin_addr.s_addr = val; - if (which != RTA_DST || + inet_aton(s, &su->sin.sin_addr)) { + val = su->sin.sin_addr.s_addr; + if (which != RTA_DST || forcehost || inet_lnaof(su->sin.sin_addr) != INADDR_ANY) return (1); else { @@ -1048,7 +1025,7 @@ getaddr(which, s, hpp) ((val = inet_network(s)) != INADDR_NONE || ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) { netdone: - inet_makenetandmask(val, &su->sin, 0); + inet_makenetandmask(val, &su->sin, (struct sockaddr_in *)&so_mask, 0); return (0); } hp = gethostbyname(s);