1-- 2-- Copyright (C) 2011, 2012 secunet Security Networks AG 3-- Copyright (C) 2011, 2012 Reto Buerki <reet@codelabs.ch> 4-- Copyright (C) 2011, 2012 Adrian-Ken Rueegsegger <ken@codelabs.ch> 5-- 6-- This program is free software; you can redistribute it and/or modify it 7-- under the terms of the GNU General Public License as published by the 8-- Free Software Foundation; either version 2 of the License, or (at your 9-- option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 10-- 11-- This program is distributed in the hope that it will be useful, but 12-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14-- for more details. 15-- 16-- As a special exception, if other files instantiate generics from this 17-- unit, or you link this unit with other files to produce an 18-- executable this unit does not by itself cause the resulting 19-- executable to be covered by the GNU General Public License. This 20-- exception does not however invalidate any other reasons why the 21-- executable file might be covered by the GNU Public License. 22-- 23 24with Anet.Byte_Swapping; 25with Anet.Constants; 26with Anet.Util; 27 28package body Anet.UDP is 29 30 use Ada.Streams; 31 32 type Raw_UDP_Hdr_Type is record 33 Source : Double_Byte; 34 Dest : Double_Byte; 35 Len : Double_Byte; 36 Check : Double_Byte; 37 end record; 38 -- Raw UDP header. 39 40 for Raw_UDP_Hdr_Type use record 41 Source at 0 range 0 .. 15; 42 Dest at 2 range 0 .. 15; 43 Len at 4 range 0 .. 15; 44 Check at 6 range 0 .. 15; 45 end record; 46 47 for Raw_UDP_Hdr_Type'Size use 64; 48 49 subtype Raw_UDP_Hdr_Buffer_Type is 50 Stream_Element_Array (1 .. UDP_Header_Length); 51 52 type Pseudo_Hdr_Type is record 53 Source_Address : IPv4_Addr_Type; 54 Dest_Address : IPv4_Addr_Type; 55 Reserved : Byte; 56 Protocol : Byte; 57 Length : Double_Byte; 58 end record; 59 -- Pseudo header used for checksum calculation/verification. 60 61 for Pseudo_Hdr_Type use record 62 Source_Address at 0 range 0 .. 31; 63 Dest_Address at 4 range 0 .. 31; 64 Reserved at 8 range 0 .. 7; 65 Protocol at 9 range 0 .. 7; 66 Length at 10 range 0 .. 15; 67 end record; 68 69 for Pseudo_Hdr_Type'Size use 96; 70 for Pseudo_Hdr_Type'Alignment use 1; 71 72 subtype Pseudo_Buffer_Type is Stream_Element_Array 73 (1 .. Pseudo_Hdr_Type'Object_Size / Stream_Element'Object_Size); 74 75 function Compute_Checksum 76 (Hdr_Buffer : Raw_UDP_Hdr_Buffer_Type; 77 Payload : Ada.Streams.Stream_Element_Array; 78 Src_IP : IPv4_Addr_Type; 79 Dst_IP : IPv4_Addr_Type) 80 return Double_Byte; 81 -- Calculate UDP checksum for given UDP header and payload. 82 83 ------------------------------------------------------------------------- 84 85 function Compute_Checksum 86 (Hdr_Buffer : Raw_UDP_Hdr_Buffer_Type; 87 Payload : Ada.Streams.Stream_Element_Array; 88 Src_IP : IPv4_Addr_Type; 89 Dst_IP : IPv4_Addr_Type) 90 return Double_Byte 91 is 92 Pseudo_Buffer : Pseudo_Buffer_Type; 93 Pseudo_Hdr : Pseudo_Hdr_Type; 94 for Pseudo_Hdr'Address use Pseudo_Buffer'Address; 95 96 subtype Pseudo_Hdr_Idx is Stream_Element_Offset range 97 1 .. Pseudo_Buffer'Length; 98 99 subtype UDP_Hdr_Idx is Stream_Element_Offset range 100 Pseudo_Hdr_Idx'Last + 1 .. Pseudo_Hdr_Idx'Last + Hdr_Buffer'Length; 101 102 Chksum_Buffer : Stream_Element_Array 103 (1 .. Pseudo_Buffer'Length + Hdr_Buffer'Length + Payload'Length); 104 begin 105 Pseudo_Hdr.Source_Address := Src_IP; 106 Pseudo_Hdr.Dest_Address := Dst_IP; 107 Pseudo_Hdr.Reserved := 0; 108 Pseudo_Hdr.Protocol := Constants.Sys.IPPROTO_UDP; 109 Pseudo_Hdr.Length := Byte_Swapping.Host_To_Network 110 (Input => Payload'Length + Hdr_Buffer'Length); 111 112 Chksum_Buffer (Pseudo_Hdr_Idx'Range) := Pseudo_Buffer; 113 Chksum_Buffer (UDP_Hdr_Idx'Range) := Hdr_Buffer; 114 Chksum_Buffer (UDP_Hdr_Idx'Last + 1 .. Chksum_Buffer'Last) := Payload; 115 116 return Util.Calculate_One_Complement (Data => Chksum_Buffer); 117 end Compute_Checksum; 118 119 ------------------------------------------------------------------------- 120 121 function Create_Header 122 (Payload : Ada.Streams.Stream_Element_Array; 123 Src_IP : IPv4_Addr_Type; 124 Dst_IP : IPv4_Addr_Type; 125 Src_Port : Port_Type; 126 Dst_Port : Port_Type) 127 return Ada.Streams.Stream_Element_Array 128 is 129 Hdr_Buffer : Raw_UDP_Hdr_Buffer_Type; 130 for Hdr_Buffer'Alignment use 16; 131 132 UDP_Hdr : Raw_UDP_Hdr_Type; 133 for UDP_Hdr'Address use Hdr_Buffer'Address; 134 begin 135 UDP_Hdr.Check := 0; 136 UDP_Hdr.Source := Byte_Swapping.Host_To_Network 137 (Input => Double_Byte (Src_Port)); 138 UDP_Hdr.Dest := Byte_Swapping.Host_To_Network 139 (Input => Double_Byte (Dst_Port)); 140 UDP_Hdr.Len := Byte_Swapping.Host_To_Network 141 (Input => Payload'Length + Hdr_Buffer'Length); 142 UDP_Hdr.Check := Byte_Swapping.Host_To_Network 143 (Input => Compute_Checksum 144 (Hdr_Buffer => Hdr_Buffer, 145 Payload => Payload, 146 Src_IP => Src_IP, 147 Dst_IP => Dst_IP)); 148 149 return Hdr_Buffer; 150 end Create_Header; 151 152 ------------------------------------------------------------------------- 153 154 procedure Validate_Checksum 155 (Packet : Ada.Streams.Stream_Element_Array; 156 Src_IP : IPv4_Addr_Type; 157 Dst_IP : IPv4_Addr_Type) 158 is 159 Hdr_Buffer : Raw_UDP_Hdr_Buffer_Type; 160 for Hdr_Buffer'Alignment use 16; 161 162 UDP_Hdr : Raw_UDP_Hdr_Type; 163 for UDP_Hdr'Address use Hdr_Buffer'Address; 164 165 Chk_Pkt, Chk_Calc : Double_Byte; 166 begin 167 Hdr_Buffer := Packet 168 (Packet'First .. Packet'First + UDP_Header_Length - 1); 169 170 if UDP_Hdr.Check = 0 then 171 return; 172 end if; 173 174 Chk_Pkt := Byte_Swapping.Network_To_Host (Input => UDP_Hdr.Check); 175 UDP_Hdr.Check := 0; 176 177 Chk_Calc := Compute_Checksum 178 (Hdr_Buffer => Hdr_Buffer, 179 Payload => Packet 180 (Packet'First + UDP_Header_Length .. Packet'Last), 181 Src_IP => Src_IP, 182 Dst_IP => Dst_IP); 183 184 if Chk_Calc /= Chk_Pkt then 185 raise Invalid_UDP_Packet with "UDP header checksum" & Chk_Pkt'Img 186 & " invalid, should be" & Chk_Calc'Img; 187 end if; 188 end Validate_Checksum; 189 190end Anet.UDP; 191