前段時間想瞭解下Linux如何配置成網關,網上很多資料,設定也只有幾步,相當簡單,並沒有碰到什麼大問題。
但是測試是否配置成功時,糾結了一下。當時是通過在此Linux網關的LAN口下再添加一台PC,目的只是ping下網關的WAN口,看是否能夠正常轉寄包。
但是添加一台PC的作用僅僅是執行一條ping命令,也太大材小用了吧 難道就不能直接在此Linux網關上直接測試嗎?當時問同事,說ping有個-I選項可以指定源地址,但是通過man ping發現其對-I參數說明得不是很明白(反正我是沒看懂,汗):
-I interface address Set source address to specified interface address. Argument may be numeric IP address or name of device. When pinging IPv6 link- local address this option is required.
按照man,此選項參數可以是裝置名稱或者IP:如果是裝置名稱如eth0,則設定ping包的源地址是eth0的IP地址;如果是IP,則ping包的源地址就是此IP地址(當然此IP要在此裝置存在)。
但是在我印象中,-I eth0指的是從eth0出去;-I IP沒用過,不知道還可以這樣子。既然對文檔不是很明白,直接看下代碼吧。
參數解析
判斷是否IP,不是則認為是裝置名稱:
if (inet_pton(AF_INET, optarg, &source.sin_addr) > 0)options |= F_STRICTSOURCE;elsedevice = optarg;
若是IP,則綁定socket的源地址:
if ((options&F_STRICTSOURCE) && bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) {perror("bind");exit(2);}
若是裝置名稱,則設定出去的網口:
if (source.sin_addr.s_addr == 0) {socklen_t alen;struct sockaddr_in dst = whereto;int probe_fd = socket(AF_INET, SOCK_DGRAM, 0);if (probe_fd < 0) {perror("socket");exit(2);}if (device) {struct ifreq ifr;memset(&ifr, 0, sizeof(ifr));strncpy(ifr.ifr_name, device, IFNAMSIZ-1);if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1) {if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) {struct ip_mreqn imr;if (ioctl(probe_fd, SIOCGIFINDEX, &ifr) < 0) {fprintf(stderr, "ping: unknown iface %s\n", device);exit(2);}memset(&imr, 0, sizeof(imr));imr.imr_ifindex = ifr.ifr_ifindex;if (setsockopt(probe_fd, SOL_IP, IP_MULTICAST_IF, &imr, sizeof(imr)) == -1) {perror("ping: IP_MULTICAST_IF");exit(2);}}}}
if (device) {struct ifreq ifr;memset(&ifr, 0, sizeof(ifr));strncpy(ifr.ifr_name, device, IFNAMSIZ-1);if (ioctl(icmp_sock, SIOCGIFINDEX, &ifr) < 0) {fprintf(stderr, "ping: unknown iface %s\n", device);exit(2);}cmsg.ipi.ipi_ifindex = ifr.ifr_ifindex;cmsg_len = sizeof(cmsg);}
從以上程式碼片段可以看出,-I eth0是指定出口,-I IP是指定源IP。本人實際測試結果也是這樣的,指定IP是能夠ping通,裝置名稱則不通:
eth0:200.200.98.41eth1:172.22.22.12$ ping -I 200.200.98.41 172.22.22.12PING 172.22.22.12 (172.22.22.12) from 200.200.98.41 : 56(84) bytes of data.64 bytes from 172.22.22.12: icmp_seq=1 ttl=64 time=0.055 ms64 bytes from 172.22.22.12: icmp_seq=2 ttl=64 time=0.056 ms64 bytes from 172.22.22.12: icmp_seq=3 ttl=64 time=0.049 ms^C--- 172.22.22.12 ping statistics ---3 packets transmitted, 3 received, 0% packet loss, time 2642msrtt min/avg/max/mdev = 0.049/0.053/0.056/0.006 ms$ sudo ping -I eth0 172.22.22.12PING 172.22.22.12 (172.22.22.12) from 200.200.98.41 eth0: 56(84) bytes of data.From 200.200.98.41 icmp_seq=2 Destination Host UnreachableFrom 200.200.98.41 icmp_seq=3 Destination Host UnreachableFrom 200.200.98.41 icmp_seq=4 Destination Host Unreachable
由於時間倉促,setsockopt和ioctl的含義沒有詳細去看,若有錯誤,歡迎指正!