1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44:
45:
46: 47: 48: 49:
50:
51: #include <t2ex/socket.h>
52: #include <tk/tkernel.h>
53:
54: #include <stdio.h>
55: #include <strings.h>
56:
57: #include "util.h"
58:
59:
60: struct icmp_state {
61: short xid;
62: int seq;
63: SYSTIM start_time;
64: };
65:
66: struct icmp_packet {
67: struct ip ip;
68: struct icmp icmp;
69: };
70:
71: static void init_icmp_state(struct icmp_state* state)
72: {
73: bzero(state, sizeof *state);
74:
75: state->xid = (short)net_random();
76: }
77:
78: static int recv_icmp_echo_reply(int sd, struct icmp_state* state, int hop)
79: {
80: struct icmp_packet* p;
81: char buf[2048];
82: int re;
83: int i;
84: fd_set fds;
85: struct timeval tv;
86: SYSTIM tim;
87: int type;
88: char rbuf[18];
89:
90: bzero(buf, sizeof buf);
91: FD_ZERO(&fds);
92: FD_SET(sd, &fds);
93:
94: tv.tv_sec = hop == 0 ? 1 : 3;
95: tv.tv_usec = 0;
96:
97: for(i = 0; i < 3; i++) {
98: re = so_select(sd+1, &fds, NULL, NULL, &tv);
99: DEBUG_PRINT(("recv_icmp_echo_reply: so_select = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
100: if ( re < 0 ) {
101: return re;
102: } else if ( re == 0 ) {
103:
104: } else {
105: re = so_recv(sd, buf, sizeof buf, 0);
106: DEBUG_PRINT(("recv_icmp_echo_reply: so_recv = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
107:
108: p = (struct icmp_packet*)buf;
109:
110: type = p->icmp.icmp_type;
111: if ( (type != ICMP_ECHOREPLY && type != ICMP_TIMXCEED) || (p->icmp.icmp_type == ICMP_ECHOREPLY && (p->icmp.icmp_id != state->xid || p->icmp.icmp_seq != state->seq ) ) ) {
112: DEBUG_PRINT(("recv_icmp_echo_reply: type=%d, id=%x:%x, seq=%d:%d\n", type, p->icmp.icmp_id, state->xid, p->icmp.icmp_seq, state->seq));
113: break;
114: }
115:
116: tk_get_tim(&tim);
117: if ( hop == 0 ) {
118: printf("ICMP reply from %s: %d bytes %d ms TTL=%d\n", inet_ntop(AF_INET, &p->ip.ip_src, rbuf, sizeof(rbuf)), re, tim.lo - state->start_time.lo, p->ip.ip_ttl);
119: } else {
120: printf(" %2d %4d ms %s\n", hop, tim.lo - state->start_time.lo, inet_ntop(AF_INET, &p->ip.ip_src, rbuf, sizeof(rbuf)));
121: }
122: if ( type == ICMP_ECHOREPLY || type == ICMP_TIMXCEED ) {
123: return type;
124: }
125: }
126: }
127:
128: if ( i == 5 ) {
129: return -1;
130: }
131:
132: return 0;
133: }
134:
135: static int send_icmp_echo_request(int sd, in_addr_t addr, struct icmp_state* state, int ttl)
136: {
137: struct icmp_packet p;
138: struct sockaddr_in sa;
139: int re;
140:
141: bzero(&p, sizeof p);
142:
143: p.ip.ip_v = IPVERSION;
144: p.ip.ip_hl = sizeof p.ip >> 2;
145: p.ip.ip_len = sizeof p;
146: p.ip.ip_id = state->xid;
147: p.ip.ip_ttl = ttl != 0 ? ttl : 255;
148: p.ip.ip_p = IPPROTO_ICMP;
149: p.ip.ip_dst.s_addr = addr;
150:
151: p.icmp.icmp_type = ICMP_ECHO;
152: p.icmp.icmp_id = state->xid;
153: p.icmp.icmp_seq = ++state->seq;
154: p.icmp.icmp_cksum = checksum((unsigned short*)&p.icmp, sizeof p.icmp);
155:
156: bzero(&sa, sizeof sa);
157: sa.sin_len = sizeof sa;
158: sa.sin_family = AF_INET;
159: sa.sin_addr.s_addr = addr;
160:
161: tk_get_tim(&state->start_time);
162:
163: printf("sending ICMP packet: id=%x, seq=%d\n", state->xid, state->seq);
164: re = so_sendto(sd, &p, sizeof p, 0, (struct sockaddr*)&sa, sizeof sa);
165: DEBUG_PRINT(("send_icmp_echo_request: so_sendto = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
166:
167: return re;
168: }
169:
170: void ping(in_addr_t addr)
171: {
172: struct icmp_state state;
173: int sender, receiver;
174: int re;
175: int on = 1;
176:
177: init_icmp_state(&state);
178:
179: sender = so_socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
180: DEBUG_PRINT(("ping: so_socket = %d(%d, %d)\n", sender, MERCD(sender), SERCD(sender)));
181: receiver = so_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
182: DEBUG_PRINT(("ping: so_socket = %d(%d, %d)\n", receiver, MERCD(receiver), SERCD(receiver)));
183:
184: re = so_setsockopt(sender, IPPROTO_IP, IP_HDRINCL, &on, sizeof on);
185: DEBUG_PRINT(("ping: so_setsockopt = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
186:
187: send_icmp_echo_request(sender, addr, &state, 0);
188: recv_icmp_echo_reply(receiver, &state, 0);
189:
190: so_close(sender);
191: so_close(receiver);
192: }
193:
194: void traceroute(in_addr_t addr)
195: {
196: struct icmp_state state;
197: int sender, receiver;
198: int hop;
199: int re;
200: int on = 1;
201: struct in_addr a;
202: char rbuf[18];
203:
204: init_icmp_state(&state);
205:
206: sender = so_socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
207: DEBUG_PRINT(("traceroute: so_socket = %d(%d, %d)\n", sender, MERCD(sender), SERCD(sender)));
208: receiver = so_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
209: DEBUG_PRINT(("traceroute: so_socket = %d(%d, %d)\n", receiver, MERCD(receiver), SERCD(receiver)));
210:
211: re = so_setsockopt(sender, IPPROTO_IP, IP_HDRINCL, &on, sizeof on);
212: DEBUG_PRINT(("traceroute: so_setsockopt = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
213:
214: a.s_addr = addr;
215: printf("traceroute to %s, 30 hops max\n", inet_ntop(AF_INET, &a, rbuf, sizeof(rbuf)));
216: for(hop = 1; hop <= 30; hop++) {
217: if ( hop != 1 ) {
218: tk_dly_tsk(1000);
219: }
220: send_icmp_echo_request(sender, addr, &state, hop);
221: re = recv_icmp_echo_reply(receiver, &state, hop);
222: if ( re == ICMP_ECHOREPLY ) {
223: break;
224: }
225: }
226:
227: so_close(sender);
228: so_close(receiver);
229: }