! IP module for INet process, GDMR, Feb/March 1987, Oct 1988 ! Now includes ICMP module. ! Ignores options on input, never sends any options. ! Should do fragmentation/reassembly !%option "-NonStandard-NoCheck-NoTrace-NoDiag-NoStack-NoLine" %option "-NonStandard-NoCheck" %constinteger ARP lives = 4 %include "INet:Formats.Inc" %include "INet:Utility.Inc" %include "INet:Stats.Inc" %include "INet:Control.Inc" %include "INet:INet.Inc" %externalintegerspec control %externalinteger slow IP address = 0 %externalinteger slow network = 0 %externalinteger ether IP address = 0 %routinespec ICMP inbound(%record(buffer fm)%name b) %externalroutinespec TCP inbound(%record(buffer fm)%name b) %externalroutinespec UDP inbound(%record(buffer fm)%name b) %externalroutinespec slow ether outbound(%record(buffer fm)%name b) %externalroutinespec ether outbound(%record(buffer fm)%name b) %externalrecord(INet statistics fm)%spec stats %routine dump IP header(%record(IP header fm) h, %string(31) text) printstring(text) printstring(" IP header version "); write(h_IHL >> 4, 0) printstring(", size "); write(h_IHL & 15, 0) printstring(", TOS "); write(h_type of service, 0) printstring(", claimed length "); write(h_total length, 0) newline printstring("ID "); write(h_identification, 0) printstring(", fragment "); write(h_fragment offset, 0) printstring(", TTL "); write(h_TTL, 0) printstring(", prot "); write(h_protocol, 0) newline printstring("Source "); print inet address(h_source) printstring(", destination "); print inet address(h_destination) newline %end %externalroutinespec find route(%integer target, %integername gate, via) %externalintegerfn IP source for(%integer d) %result = slow IP address %if d & 16_FFFFFF00 = slow network %result = slow IP address %if ether IP address = 0; ! No 10Meg, use slow %result = ether IP address %end %routine IP send(%record(buffer fm)%name b) %integer c, via !! printstring("IP send to "); print INet address(b_IP peer); newline %if control & trace IP out # 0 %start dump IP header(b_IP header, "Outbound") %finish b_IP header_TTL = b_IP header_TTL - 1 release buffer(b) %and %return %if b_IP header_TTL = 0; ! Expired stats_IP packets out = stats_IP packets out + 1 stats_IP bytes out = stats_IP bytes out + b_IP bytes b_IP header_checksum = 0; ! Meantime !N! net order short(b_IP header_total length) !N! ! fragment offset assumed 0 !N! net order long(b_IP header_source) !N! net order long(b_IP header_destination) c = calculate checksum(b_IP header, 20); ! Header checksum only b_IP header_checksum <- \c b_IP header_checksum <- 16_FFFF %if b_IP header_checksum = 0; ! Use -0 find route(b_IP peer, b_IP target, via) b_IP target = b_IP peer %if b_IP target = 0; ! Direct !! %if b_IP target # b_IP peer %start !! printstring("Route for "); print INet address(b_IP peer) !! printstring(" via "); print INet address(b_IP target); newline !! %finish %if b_IP target & 16_FFFFFF00 = slow network %start slow ether outbound(b) %else ether outbound(b) %finish %end %externalroutine IP inbound(%record(buffer fm)%name b) %integer checksum, header size, host, net, class !L! lights or A(IP light) !! printstring("Inbound IP packet, size ") !! write(b_bytes, 0); newline !! dump(byteinteger(addr(b_IP header)), b_bytes) header size = (b_IP header_IHL & 15) * 4 !! printstring("Header size is "); write(header size, 0); newline ! check the checksum. checksum = calculate checksum(b_IP header, header size) %if checksum # 0 %and checksum # 16_FFFF %start ! Dud checksum (beware ONES-complement) !N! net order long(b_IP header_source) !! pdate !! printstring("Dud IP checksum "); write(checksum, 0) !! printstring(" from "); print inet address(b_IP header_source) !! newline ! If the checksum was wrong then maybe the source address is wrong ! too, so we log it to the non-peer area. ! sp_IP checksum errors = sp_IP checksum errors + 1 release buffer(b) -> out %finish ! Convert things from net order !N! net order short(b_IP header_total length) !N! net order short(b_IP header_fragment offset) !N! net order long(b_IP header_source) !N! net order long(b_IP header_destination) %if control & trace IP in # 0 %start !! printstring("IP from "); print INet address(b_IP header_source) !! printstring(" for "); print INet address(b_IP header_destination) !! printstring(" TTL "); write(b_IP header_TTL, 0); newline dump IP header(b_IP header, "Inbound") %finish %if b_IP header_source & 16_FF000000 = 0 %start ! A Sun booting -- throw it away !! printstring("Sun booting (probably)"); newline stats_IP other errors = stats_IP other errors + 1 release buffer(b) -> out %finish b_IP peer = b_IP header_source %if b_IP header_fragment offset & 2_0011 1111 1111 1111 # 0 %start ! Fragmented -- dump it (*meantime*) !! pdate !! printstring("Fragmented IP packet received from ") !! print inet address(b_IP peer) !! printstring(" -- dumping"); newline stats_IP fragmented packets = stats_IP fragmented packets + 1 stats_IP fragmented bytes = stats_IP fragmented bytes + b_bytes ! Drop it unconditionally, for now stats_IP fragments dropped = stats_IP fragments dropped + 1 stats_IP fragmented bytes dropped = %c stats_IP fragmented bytes dropped + b_bytes release buffer(b) -> out %finish ! %if 46 <= b_IP header_total length # b_bytes %start ! ! Received length wrong ! !! pdate ! !! printstring("Length mismatch from ") ! !! print inet address(b_IP peer) ! !! printstring(": claimed "); write(b_IP header_total length, 0) ! !! printstring(", actual "); write(b_bytes, 0); newline ! stats_IP dud lengths = stats_IP dud lengths + 1 ! ! Carry on -- assume that the IP length is the correct one. ! ! Some systems, notably cheops, appear to be padding packets to ! ! an even boundary.... ! %finish ! Validate the destination. >> SHOULD BOMB-PROOF THIS << split INet address(b_IP header_destination, host, net, class) %if host = 0 %start ! Old-style ...0.0 broadcast !! printstring("Old-style IP broadcast from ") !! print inet address(b_IP peer) !! printstring(", protocol "); write(b_IP header_protocol, 0) !! newline stats_IP old broadcasts = stats_IP old broadcasts + 1 %else %if host = -1 %or host = new broadcast mask(class) ! New-style ...255.255 broadcast !! printstring("New-style IP broadcast from ") !! print inet address(b_IP peer) !! printstring(", protocol "); write(b_IP header_protocol, 0) !! newline stats_IP new broadcasts = stats_IP new broadcasts + 1 %else %if b_IP header_destination # ether IP address %c %and b_IP header_destination # slow IP address ! Not for us. Forward it. (??!) !! pdate !! printstring("Forwarding IP: destination ") !! print inet address(b_IP header_destination) !! printstring(", source "); print inet address(b_IP header_source) !! newline stats_IP packets routed = stats_IP packets routed + 1 stats_IP bytes routed = stats_IP bytes routed + b_bytes b_IP peer = b_IP header_destination IP send(b) -> out %finish ! Now forward the validated header... b_header2 == record(addr(b_IP header) + header size) b_IP bytes = b_IP header_total length - header size stats_IP packets in = stats_IP packets in + 1 stats_IP bytes in = stats_IP bytes in + b_IP bytes %if b_IP header_protocol = IP TCP protocol %start !! printstring("IP TCP"); newline TCP inbound(b) %else %if b_IP header_protocol = IP UDP protocol !! printstring("IP UDP"); newline UDP inbound(b) %else %if b_IP header_protocol = IP ICMP protocol !! printstring("IP ICMP"); newline ICMP inbound(b) %else ! Something unknown !! pdate !! printstring("Unknown protocol type "); write(b_IP header_protocol, 0) !! printstring(" from "); print inet address(b_IP peer) !! newline stats_IP dud protocols = stats_IP dud protocols + 1 release buffer(b) %finish out: !L! lights and A(\IP light) %end %externalroutine IP outbound(%record(buffer fm)%name b) %owninteger outbound identification = 0 !L! lights or B(IP light) !! printstring("IP outbound for ") !! print inet address(b_IP peer); newline !! dump(byteinteger(addr(b_header 2)), b_IP bytes) %if b_IP tag = 0 %start outbound identification = (outbound identification + 1) & 16_FFFF outbound identification = 1 %if outbound identification = 0 b_IP tag = outbound identification %finish b_bytes = b_IP bytes + 20 b_IP header == record(addr(b_header 2) - 20) b_IP header_IHL = 16_45 b_IP header_type of service = 0 b_IP header_total length = b_bytes b_IP header_identification <- b_IP tag b_IP header_fragment offset = 0 b_IP header_TTL = 255 b_IP header_protocol = b_protocol b_IP header_source = IP source for(b_IP peer) b_IP header_destination = b_IP peer !! dump IP header(b_IP header) ! No options IP send(b) !L! lights and B(\IP light) %end ! ICMP follows.... %constinteger ICMP echo reply = 0 %constinteger ICMP destination unreachable = 3 %constinteger ICMP source quench = 4 %constinteger ICMP redirect = 5 %constinteger ICMP echo = 8 %constinteger ICMP time exceeded = 11 %constinteger ICMP parameter problem = 12 %constinteger ICMP timestamp = 13 %constinteger ICMP timestamp reply = 14 %constinteger ICMP information request = 15 %constinteger ICMP information reply = 16 %constinteger ICMP protocol unreachable = 2 %constinteger ICMP port unreachable = 3 %conststring(31)%array ICMP message text(0 : 16) = { 0} "Echo reply", { 1} "?? 1", { 2} "?? 2", { 3} "Destination unreachable", { 4} "Source quench", { 5} "Redirect", { 6} "?? 6", { 7} "?? 7", { 8} "Echo", { 9} "?? 9", {10} "?? 10", {11} "Time exceeded", {12} "Parameter problem", {13} "Timestamp", {14} "Timestamp reply", {15} "Information request", {16} "Information reply" %owninteger ICMP echo sequence = 0 %externalroutine ICMP inbound(%record(buffer fm)%name b) %string(127) message, source %integer c, x, host, net, class !L! lights or A(ICMP light) !! printstring("ICMP inbound from ") !! print inet address(b_IP header_source); newline !! dump(byteinteger(addr(b_ICMP header)), b_IP bytes) message = "ICMP: from " . inet address to S(b_IP header_source) !source = INet address to name(b_IP header_source) !message = message . " (" . source . ")" %if source # "" split INet address(b_IP header_destination, host, net, class) message = message . " (broadcast??)" %if b_flags & broadcast flag # 0 message = message . " -- " %if b_IP bytes < 8 %start pdate printstring("Short ICMP message from ") print inet address(b_IP header_source); newline stats_ICMP errors in = stats_ICMP errors in + 1 release buffer(b) -> out %finish stats_ICMP in = stats_ICMP in + 1 %if b_ICMP header_type = ICMP echo %start ! Send echo reply %if b_flags & broadcast flag = 0 %start ! Don't reply to broadcasts b_ICMP header_type = ICMP echo reply b_ICMP header_checksum = 0 c = calculate checksum(b_ICMP header, b_IP bytes) b_ICMP header_checksum <- \c stats_ICMP out = stats_ICMP out + 1 !! printstring("Sending echo reply to ") !! print inet address(b_IP peer); newline b_protocol = IP ICMP protocol b_next queue == nil IP outbound(b) -> out %finish %else %if b_ICMP header_type = ICMP echo reply printstring(message); printstring("echo reply") newline %else %if b_ICMP header_type = ICMP timestamp ! Send timestamp reply %if b_flags & broadcast flag = 0 %start ! Don't reply to broadcasts x = b_ICMP header_originate timestamp !N! net order long(x) b_ICMP header_type = ICMP timestamp reply b_ICMP header_receive timestamp = generate timestamp !N! net order long(b_ICMP header_receive timestamp) b_ICMP header_transmit timestamp = b_ICMP header_receive timestamp b_ICMP header_checksum = 0 c = calculate checksum(b_ICMP header, b_IP bytes) b_ICMP header_checksum <- \c stats_ICMP out = stats_ICMP out + 1 !! printstring("Sending timestamp reply to ") !! print inet address(b_IP peer); newline b_protocol = IP ICMP protocol b_next queue == nil IP outbound(b) -> out %finish %else %if b_ICMP header_type = ICMP timestamp reply !N! net order long(b_ICMP header_originate timestamp) !N! net order long(b_ICMP header_receive timestamp) !N! net order long(b_ICMP header_transmit timestamp) message = message . "timestamp reply: " . %c convert timestamp(b_ICMP header_originate timestamp) . ", " . %c convert timestamp(b_ICMP header_receive timestamp) . ", " . %c convert timestamp(b_ICMP header_transmit timestamp) printstring(message); newline %finish release buffer(b) out: !L! lights and A(\ICMP light) %end ! ICMP outbound (user requests) %recordformat ICMP request fm(%integer code, target) %externalroutine ICMP outbound(%record(buffer fm)%name b) %record(ICMP request fm)%name request %integer c !L! lights or B(ICMP light) request == record(addr(b_data start)) !! printstring("ICMP outbound for ") !! print inet address(request_target); newline b_ICMP header == record(addr(b_data(32))) b_ICMP header = 0 b_IP peer = request_target %if request_code = ICMP ping request %start b_ICMP header_type = ICMP echo b_ICMP header_code = 0 ICMP echo sequence = ICMP echo sequence + 1 b_ICMP header_sequence number = ICMP echo sequence c = calculate checksum(b_ICMP header, 8) b_ICMP header_checksum <- \c b_data bytes = 0; b_IP bytes = 8; b_protocol = IP ICMP protocol b_next queue == nil IP outbound(b) stats_ICMP out = stats_ICMP out + 1 %else %if request_code = ICMP timestamp request b_ICMP header_type = ICMP timestamp b_ICMP header_code = 0 ICMP echo sequence = ICMP echo sequence + 1 b_ICMP header_sequence number = ICMP echo sequence b_ICMP header_originate timestamp = generate timestamp !N! net order long(b_ICMP header_originate timestamp) c = calculate checksum(b_ICMP header, 20) b_ICMP header_checksum <- \c b_data bytes = 0; b_IP bytes = 20; b_protocol = IP ICMP protocol b_next queue == nil IP outbound(b) stats_ICMP out = stats_ICMP out + 1 %else !! printstring("Unknown ICMP request code ") !! phex(request_code); newline stats_ICMP errors out = stats_ICMP errors out + 1 release buffer(b) %finish !L! lights and B(\ICMP light) %end %end %of %file