View Javadoc
1   /*
2    * Copyright 2015 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.channel.unix;
17  
18  import java.net.Inet6Address;
19  import java.net.InetAddress;
20  import java.net.InetSocketAddress;
21  import java.net.UnknownHostException;
22  
23  /**
24   * <strong>Internal usage only!</strong>
25   */
26  public final class NativeInetAddress {
27      private static final byte[] IPV4_MAPPED_IPV6_PREFIX = {
28              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff };
29      final byte[] address;
30      final int scopeId;
31  
32      public static NativeInetAddress newInstance(InetAddress addr) {
33          byte[] bytes = addr.getAddress();
34          if (addr instanceof Inet6Address) {
35              return new NativeInetAddress(bytes, ((Inet6Address) addr).getScopeId());
36          } else {
37              // convert to ipv4 mapped ipv6 address;
38              return new NativeInetAddress(ipv4MappedIpv6Address(bytes));
39          }
40      }
41  
42      public NativeInetAddress(byte[] address, int scopeId) {
43          this.address = address;
44          this.scopeId = scopeId;
45      }
46  
47      public NativeInetAddress(byte[] address) {
48          this(address, 0);
49      }
50  
51      public byte[] address() {
52          return address;
53      }
54  
55      public int scopeId() {
56          return scopeId;
57      }
58  
59      public static byte[] ipv4MappedIpv6Address(byte[] ipv4) {
60          byte[] address = new byte[16];
61          copyIpv4MappedIpv6Address(ipv4, address);
62          return address;
63      }
64  
65      public static void copyIpv4MappedIpv6Address(byte[] ipv4, byte[] ipv6) {
66          System.arraycopy(IPV4_MAPPED_IPV6_PREFIX, 0, ipv6, 0, IPV4_MAPPED_IPV6_PREFIX.length);
67          System.arraycopy(ipv4, 0, ipv6, 12, ipv4.length);
68      }
69  
70      public static InetSocketAddress address(byte[] addr, int offset, int len) {
71          // The last 4 bytes are always the port
72          final int port = decodeInt(addr, offset + len - 4);
73          final InetAddress address;
74          try {
75              switch (len) {
76                  // 8 bytes:
77                  // - 4  == ipaddress
78                  // - 4  == port
79                  case 8:
80                      byte[] ipv4 = new byte[4];
81                      System.arraycopy(addr, offset, ipv4, 0, 4);
82                      address = InetAddress.getByAddress(ipv4);
83                      break;
84  
85                  // 24 bytes:
86                  // - 16  == ipaddress
87                  // - 4   == scopeId
88                  // - 4   == port
89                  case 24:
90                      byte[] ipv6 = new byte[16];
91                      System.arraycopy(addr, offset, ipv6, 0, 16);
92                      int scopeId = decodeInt(addr, offset + len  - 8);
93                      // Only include the scopeId if its either non 0 or if this is a link-local address
94                      // as scopeId is only supported with it:
95                      // See also https://man7.org/linux/man-pages/man7/ipv6.7.html
96                      if (scopeId != 0 || (ipv6[0] == (byte) 0xfe && ipv6[1] == (byte) 0x80)) {
97                          address = Inet6Address.getByAddress(null, ipv6, scopeId);
98                      } else {
99                          address = InetAddress.getByAddress(null, ipv6);
100                     }
101                     break;
102                 default:
103                     throw new Error();
104             }
105             return new InetSocketAddress(address, port);
106         } catch (UnknownHostException e) {
107             throw new Error("Should never happen", e);
108         }
109     }
110 
111     static int decodeInt(byte[] addr, int index) {
112         return  (addr[index]     & 0xff) << 24 |
113                 (addr[index + 1] & 0xff) << 16 |
114                 (addr[index + 2] & 0xff) <<  8 |
115                 addr[index + 3] & 0xff;
116     }
117 }