Some time ago I want to know how to configure Linux as a gateway. There are a lot of information on the Internet and there are only a few steps to set up, which is quite simple and has not encountered any major problems.
However, when testing whether the configuration is successful, I am confused. At that time, a PC was added to the LAN port of the Linux gateway to ping the WAN port of the gateway to check whether packets can be forwarded normally.
However, the function of adding a PC is only to execute a ping command, which is too small to be used. Isn't it possible to directly test it on the Linux Gateway? At that time, I asked my colleague that ping had a-I option to specify the source address. However, man Ping found that the-I parameter was not very clear (I didn't understand it anyway, Khan ):
-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.
According to man, this option parameter can be the device name or IP Address: if the device name is eth0, set the source address of the ping packet to the IP address of eth0; if it is an IP address, the source address of the ping packet is the IP address (of course, this IP address must exist on this device ).
But in my impression,-I eth0 refers to getting out of eth0;-I ip has never been used, and I don't know whether it can be like this. Since the document is not very clear, let's look at the Code directly.
Parameter Parsing
Determines whether the IP address is used. If not, the device name is used:
if (inet_pton(AF_INET, optarg, &source.sin_addr) > 0)options |= F_STRICTSOURCE;elsedevice = optarg;
If it is an IP address, the source address of the socket is bound:
if ((options&F_STRICTSOURCE) && bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) {perror("bind");exit(2);}
If the device name is used, set the outbound network port:
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);}
From the code snippet above, we can see that-I eth0 is the specified egress and-I IP is the specified source IP. The actual test result is as follows: the specified IP address can be pinged, and the device name cannot be pinged:
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
Due to the rush of time, the meanings of setsockopt and IOCTL are not detailed. If any errors occur, please correct them!