View Javadoc
1   /*
2    * Copyright 2020 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec.quic;
17  
18  import io.netty.util.internal.PlatformDependent;
19  import org.jetbrains.annotations.Nullable;
20  
21  import java.net.Inet4Address;
22  import java.net.Inet6Address;
23  import java.net.InetAddress;
24  import java.net.InetSocketAddress;
25  import java.net.UnknownHostException;
26  import java.nio.ByteBuffer;
27  
28  final class SockaddrIn {
29      static final byte[] IPV4_MAPPED_IPV6_PREFIX = {
30              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff };
31      static final int IPV4_ADDRESS_LENGTH = 4;
32      static final int IPV6_ADDRESS_LENGTH = 16;
33      static final byte[] SOCKADDR_IN6_EMPTY_ARRAY = new byte[Quiche.SIZEOF_SOCKADDR_IN6];
34      static final byte[] SOCKADDR_IN_EMPTY_ARRAY = new byte[Quiche.SIZEOF_SOCKADDR_IN];
35  
36      private SockaddrIn() { }
37  
38      static int cmp(long memory, long memory2) {
39          return Quiche.sockaddr_cmp(memory, memory2);
40      }
41  
42      static int setAddress(ByteBuffer memory, InetSocketAddress address) {
43          InetAddress addr = address.getAddress();
44          return setAddress(addr instanceof Inet6Address, memory, address);
45      }
46  
47      static int setAddress(boolean ipv6, ByteBuffer memory, InetSocketAddress address) {
48          if (ipv6) {
49              return SockaddrIn.setIPv6(memory, address.getAddress(), address.getPort());
50          } else {
51              return SockaddrIn.setIPv4(memory, address.getAddress(), address.getPort());
52          }
53      }
54  
55      /**
56       *
57       * struct sockaddr_in {
58       *      sa_family_t    sin_family; // address family: AF_INET
59       *      in_port_t      sin_port;   // port in network byte order
60       *      struct in_addr sin_addr;   // internet address
61       * };
62       *
63       * // Internet address.
64       * struct in_addr {
65       *     uint32_t       s_addr;     // address in network byte order
66       * };
67       *
68       */
69      static int setIPv4(ByteBuffer memory, InetAddress address, int port) {
70          int position = memory.position();
71          try {
72              // memset
73              memory.put(SOCKADDR_IN_EMPTY_ARRAY);
74  
75              memory.putShort(position + Quiche.SOCKADDR_IN_OFFSETOF_SIN_FAMILY, Quiche.AF_INET);
76              memory.putShort(position + Quiche.SOCKADDR_IN_OFFSETOF_SIN_PORT, (short) port);
77  
78              byte[] bytes = address.getAddress();
79              int offset = 0;
80              if (bytes.length == IPV6_ADDRESS_LENGTH) {
81                  // IPV6 mapped IPV4 address, we only need the last 4 bytes.
82                  offset = IPV4_MAPPED_IPV6_PREFIX.length;
83              }
84              assert bytes.length == offset + IPV4_ADDRESS_LENGTH;
85              memory.position(position + Quiche.SOCKADDR_IN_OFFSETOF_SIN_ADDR + Quiche.IN_ADDRESS_OFFSETOF_S_ADDR);
86              memory.put(bytes, offset, IPV4_ADDRESS_LENGTH);
87              return Quiche.SIZEOF_SOCKADDR_IN;
88          } finally {
89              memory.position(position);
90          }
91      }
92  
93      /**
94       * struct sockaddr_in6 {
95       *     sa_family_t     sin6_family;   // AF_INET6
96       *     in_port_t       sin6_port;     // port number
97       *     uint32_t        sin6_flowinfo; // IPv6 flow information
98       *     struct in6_addr sin6_addr;     // IPv6 address
99       *     uint32_t        sin6_scope_id; /* Scope ID (new in 2.4)
100      * };
101      *
102      * struct in6_addr {
103      *     unsigned char s6_addr[16];   // IPv6 address
104      * };
105      */
106     static int setIPv6(ByteBuffer memory, InetAddress address, int port) {
107         int position = memory.position();
108         try {
109             // memset
110             memory.put(SOCKADDR_IN6_EMPTY_ARRAY);
111 
112             memory.putShort(position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_FAMILY, Quiche.AF_INET6);
113             memory.putShort(position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_PORT, (short) port);
114 
115             // Skip sin6_flowinfo as we did memset before
116             byte[] bytes = address.getAddress();
117             int offset = Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Quiche.IN6_ADDRESS_OFFSETOF_S6_ADDR;
118 
119             if (bytes.length == IPV4_ADDRESS_LENGTH) {
120                 memory.position(position + offset);
121                 memory.put(IPV4_MAPPED_IPV6_PREFIX);
122 
123                 memory.position(position + offset + IPV4_MAPPED_IPV6_PREFIX.length);
124                 memory.put(bytes, 0, IPV4_ADDRESS_LENGTH);
125 
126                 // Skip sin6_scope_id as we did memset before
127             } else {
128                 memory.position(position + offset);
129                 memory.put(bytes, 0, IPV6_ADDRESS_LENGTH);
130 
131                 memory.putInt(position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID,
132                         ((Inet6Address) address).getScopeId());
133             }
134             return Quiche.SIZEOF_SOCKADDR_IN6;
135         } finally {
136             memory.position(position);
137         }
138     }
139 
140     @Nullable
141     static InetSocketAddress getIPv4(ByteBuffer memory, byte[] tmpArray) {
142         assert tmpArray.length == IPV4_ADDRESS_LENGTH;
143         int position = memory.position();
144 
145         try {
146             int port = memory.getShort(position + Quiche.SOCKADDR_IN_OFFSETOF_SIN_PORT) & 0xFFFF;
147             memory.position(position + Quiche.SOCKADDR_IN_OFFSETOF_SIN_ADDR + Quiche.IN_ADDRESS_OFFSETOF_S_ADDR);
148             memory.get(tmpArray);
149             try {
150                 return new InetSocketAddress(InetAddress.getByAddress(tmpArray), port);
151             } catch (UnknownHostException ignore) {
152                 return null;
153             }
154         } finally {
155             memory.position(position);
156         }
157     }
158 
159     @Nullable
160     static InetSocketAddress getIPv6(ByteBuffer memory, byte[] ipv6Array, byte[] ipv4Array) {
161         assert ipv6Array.length == IPV6_ADDRESS_LENGTH;
162         assert ipv4Array.length == IPV4_ADDRESS_LENGTH;
163         int position = memory.position();
164 
165         try {
166             int port = memory.getShort(
167                     position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_PORT) & 0xFFFF;
168             memory.position(position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Quiche.IN6_ADDRESS_OFFSETOF_S6_ADDR);
169             memory.get(ipv6Array);
170             if (PlatformDependent.equals(
171                     ipv6Array, 0, IPV4_MAPPED_IPV6_PREFIX, 0, IPV4_MAPPED_IPV6_PREFIX.length)) {
172                 System.arraycopy(ipv6Array, IPV4_MAPPED_IPV6_PREFIX.length, ipv4Array, 0, IPV4_ADDRESS_LENGTH);
173                 try {
174                     return new InetSocketAddress(Inet4Address.getByAddress(ipv4Array), port);
175                 } catch (UnknownHostException ignore) {
176                     return null;
177                 }
178             } else {
179                 int scopeId = memory.getInt(position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID);
180                 try {
181                     return new InetSocketAddress(Inet6Address.getByAddress(null, ipv6Array, scopeId), port);
182                 } catch (UnknownHostException ignore) {
183                     return null;
184                 }
185             }
186         } finally {
187             memory.position(position);
188         }
189     }
190 }