Hi,

We're soon testing DiffServ and related little QOS-features here, and I
saw the lack of easy access to setting QOS-related bits in ICMP datagrams. 

I created a patch to enable that (based on RHL iputils errata
version).  Setting both precedence and tos bits
can be done quite nicely.  Part of the code has been adapted from
traceroute (which can set tos in a similar fashion), the rest written by
me.

Comments welcome; code review (ping _is_ suid..) is also appreciated.

-- 
Pekka Savola                 "Tell me of difficulties surmounted, 
[EMAIL PROTECTED]      not those you stumble over and fall"
--- ping.c.orig Sat Oct 28 18:56:22 2000
+++ ping.c      Sat Oct 28 22:03:51 2000
@@ -89,6 +89,7 @@
 #define        MAXICMPLEN      76
 #define        MAXWAIT         10              /* max seconds to wait for response */
 #define        NROUTES         9               /* number of record route slots */
+#define TOS_MAX                255             /* 8-bit TOS field */
 
 #define        A(bit)          rcvd_tbl[(bit)>>3]      /* identify byte in array */
 #define        B(bit)          (1 << ((bit) & 0x07))   /* identify bit in byte */
@@ -135,6 +136,7 @@
 struct sockaddr_in whereto;    /* who to ping */
 int datalen = DEFDATALEN;
 int optlen = 0;
+int settos = 0;                        /* Set TOS, Precendence or other QOS options 
+*/
 int icmp_sock;                 /* socket file descriptor */
 u_char outpack[0x10000];
 char BSPACE = '\b';            /* characters written for flood */
@@ -182,7 +184,7 @@
 static int pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv);
 static u_short in_cksum(const u_short *addr, int len, u_short salt);
 static void pr_icmph(struct icmphdr *icp);
-
+static int parsetos(char *str);
 
 /*
  * tvsub --
@@ -244,7 +246,7 @@
        source.sin_family = AF_INET;
 
        preload = 0;
-       while ((ch = getopt(argc, argv, "I:LT:Rc:dfh:i:l:np:qrs:t:vbw:UVM:")) != EOF) 
{
+       while ((ch = getopt(argc, argv, "I:LT:Rc:dfh:i:l:nQ:p:qrs:t:vbw:UVM:")) != 
+EOF) {
                switch(ch) {
                case 'b':
                        broadcast_pings = 1;
@@ -322,6 +324,14 @@
                case 'q':
                        options |= F_QUIET;
                        break;
+               case 'Q':
+                       settos = parsetos(optarg);
+                       if (settos && (setsockopt(icmp_sock, IPPROTO_IP, IP_TOS,
+                                       (char *)&settos, sizeof(int)) < 0)) {
+                               fprintf(stderr, "Error setting QOS sockopts: %u\n", 
+errno);
+                               exit(2);
+                       }
+                       break;
                case 'R':
                        if (options & F_TIMESTAMP) {
                                fprintf(stderr, "Only one of -T or -R may be used\n");
@@ -1643,9 +1653,38 @@
        }
 }
 
+/* Set Type of Service (TOS) and other Quality of Service relating bits */
+int parsetos(char *str)
+{
+        register const char *cp;
+        register int tos;
+        char *ep;
+                        
+        /* handle both hex and decimal values */
+        if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
+               cp = str + 2;
+               tos = (int)strtol(cp, &ep, 16);
+        } else
+                tos = (int)strtol(str, &ep, 10);
+        
+        /* doesn't look like decimal or hex, eh? */
+        if (*ep != '\0') {     
+               fprintf(stderr, "ping: \"%s\" bad value for TOS\n", str);
+               exit(2);
+        }
+        
+        /* Note: Setting 255 or 1 gives EINVAL, so those are avoided here */
+        if (tos > TOS_MAX-1 || tos <= 1) {
+               fprintf(stderr, "ping: the decimal value of TOS bits must be 2-254 (or 
+zero)\n");
+               exit(2);
+        }
+       return(tos);                                                                   
+                                                
+}
+
+
 void usage(void)
 {
        fprintf(stderr,
-               "Usage: ping [-LRUbdfnqrvV] [-c count] [-i interval] [-w wait]\n\t[-p 
pattern] [-s packetsize] [-t ttl] [-I interface address]\n\t[ -T timestamp option ] 
host\n");
+               "Usage: ping [-LRUbdfnqrvV] [-c count] [-i interval] [-w wait]\n\t[-p 
+pattern] [-s packetsize] [-t ttl] [-I interface address]\n\t[ -T timestamp option ] [ 
+-Q tos ] host\n");
        exit(2);
 }
--- ping.8.orig Tue Sep 12 22:34:46 2000
+++ ping.8      Sat Oct 28 22:03:11 2000
@@ -18,6 +18,7 @@
 .Op Fl w Ar deadline
 .Op Fl I Ar interface address
 .Op Fl T Ar timestamp option
+.Op Fl Q Ar tos
 .Tn host
 .Sh DESCRIPTION
 .Nm Ping
@@ -101,6 +102,16 @@
 .Dq Li \-p ff
 will cause the sent packet to be filled with all
 ones.
+.It Fl Q Ar tos
+Set Quality of Service -related bits in ICMP datagrams.  
+.Ar tos
+can be either decimal or hex number.  The bits are: 0 for reserved
+(currently being redefined as congestion control), 1-4 for Type of Service
+and 5-7 for Precendence. 
+Possible settings for Type of Service are: minimal cost, ECN: 0x02, 
+reliability: 0x04, throughput: 0x08, lowdelay: 0x10.  Multiple TOS bits
+should not be set simultaneously.  Possible settings for
+special Precedence range from priority (0x20) to net control (0xe0).  
 .It Fl q
 Quiet output.
 Nothing is displayed except the summary lines at startup time and

Reply via email to