sourceroute.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. * Copyright (c) 1993 W. Richard Stevens. All rights reserved.
  3. * Permission to use or modify this software and its documentation only for
  4. * educational purposes and without fee is hereby granted, provided that
  5. * the above copyright notice appear in all copies. The author makes no
  6. * representations about the suitability of this software for any purpose.
  7. * It is provided "as is" without express or implied warranty.
  8. */
  9. #include "sock.h"
  10. #include <netinet/in_systm.h>
  11. #include <netinet/ip.h>
  12. /*
  13. * There is a fundamental limit of 9 IP addresses in a source route.
  14. * But we allocate sroute_opt[44] with room for 10 IP addresses (and
  15. * the 3-byte source route type/len/offset) because with the BSD
  16. * IP_OPTIONS socket option we can specify up to 9 addresses, followed
  17. * by the destination address. The in_pcbopts() function in the kernel
  18. * then takes the final address in the list (the destination) and moves
  19. * it to the front, as shown in Figure 9.33 of "TCP/IP Illustrated,
  20. * Volume 2". Also note that this destination address that we pass as
  21. * the final IP address in our array overrides the destination address
  22. * of the sendto() (Figure 9.28 of Volume 2).
  23. */
  24. u_char sroute_opt[44]; /* some implementations require this to be
  25. on a 4-byte boundary */
  26. u_char *optr; /* pointer into options being formed */
  27. /*
  28. * Process either the -g (loose) or -G (strict) command-line option,
  29. * specifying one hop in a source route.
  30. * Either option can be specified up to 9 times.
  31. * With IPv4 the entire source route is either loose or strict, but we
  32. * set the source route type field based on the first option encountered,
  33. * either -g or -G.
  34. */
  35. void
  36. sroute_doopt(int strict, char *argptr)
  37. {
  38. struct in_addr inaddr;
  39. struct hostent *hp;
  40. if (sroute_cnt >= 9)
  41. err_quit("too many source routes with: %s", argptr);
  42. if (sroute_cnt == 0) { /* first one */
  43. bzero(sroute_opt, sizeof(sroute_opt));
  44. optr = sroute_opt;
  45. *optr++ = strict ? IPOPT_SSRR : IPOPT_LSRR;
  46. optr++; /* we fill in the total length later */
  47. *optr++ = 4; /* ptr to first source-route address */
  48. }
  49. if (inet_aton(argptr, &inaddr) == 1) {
  50. memcpy(optr, &inaddr, sizeof(u_long)); /* dotted decimal */
  51. if (verbose)
  52. fprintf(stderr, "source route to %s\n", inet_ntoa(inaddr));
  53. } else if ( (hp = gethostbyname(argptr)) != NULL) {
  54. memcpy(optr, hp->h_addr, sizeof(u_long));/* hostname */
  55. if (verbose)
  56. fprintf(stderr, "source route to %s\n",
  57. inet_ntoa(*((struct in_addr *) hp->h_addr)));
  58. } else
  59. err_quit("unknown host: %s\n", argptr);
  60. optr += sizeof(u_long); /* for next IP addr in list */
  61. sroute_cnt++;
  62. }
  63. /*
  64. * Set the actual source route with the IP_OPTIONS socket option.
  65. * This function is called if srouce_cnt is nonzero.
  66. * The final destination goes at the end of the list of IP addresses.
  67. */
  68. void
  69. sroute_set(int sockfd)
  70. {
  71. sroute_cnt++; /* account for destination */
  72. sroute_opt[1] = 3 + (sroute_cnt * 4);/* total length, incl. destination */
  73. /* destination must be stored as final entry */
  74. memcpy(optr, &servaddr.sin_addr, sizeof(u_long));
  75. optr += sizeof(u_long);
  76. if (verbose) {
  77. fprintf(stderr, "source route to %s\n", inet_ntoa(servaddr.sin_addr));
  78. fprintf(stderr, "source route size %d bytes\n", sroute_opt[1]);
  79. }
  80. /*
  81. * The number of bytes that we pass to setsockopt() must be a multiple
  82. * of 4. Since the buffer was initialized to 0, this leaves an EOL
  83. * following the final IP address.
  84. * For optimization we could put a NOP before the 3-byte type/len/offset
  85. * field, which would then align all the IP addresses on 4-byte boundaries,
  86. * but the source routing code is not exactly in the fast path of most
  87. * routers.
  88. */
  89. while ((optr - sroute_opt) & 3)
  90. optr++;
  91. if (setsockopt(sockfd, IPPROTO_IP, IP_OPTIONS,
  92. sroute_opt, optr - sroute_opt) < 0)
  93. err_sys("setsockopt error for IP_OPTIONS");
  94. sroute_cnt = 0; /* don't call this function again */
  95. }