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.buffer.ByteBuf;
19  import io.netty.buffer.Unpooled;
20  import io.netty.util.CharsetUtil;
21  import io.netty.util.NetUtil;
22  
23  import java.net.InetSocketAddress;
24  
25  /**
26   * Insecure {@link QuicTokenHandler} which only does basic token generation / validation without any
27   * crypto.
28   *
29   * <strong>This shouldn't be used in production.</strong>
30   */
31  public final class InsecureQuicTokenHandler implements QuicTokenHandler {
32  
33      private static final String SERVER_NAME = "netty";
34      private static final byte[] SERVER_NAME_BYTES = SERVER_NAME.getBytes(CharsetUtil.US_ASCII);
35      private static final ByteBuf SERVER_NAME_BUFFER = Unpooled.unreleasableBuffer(
36              Unpooled.wrappedBuffer(SERVER_NAME_BYTES)).asReadOnly();
37  
38      // Just package-private for unit tests
39      static final int MAX_TOKEN_LEN = Quic.MAX_CONN_ID_LEN +
40              NetUtil.LOCALHOST6.getAddress().length + SERVER_NAME_BYTES.length;
41  
42      private InsecureQuicTokenHandler() {
43          Quic.ensureAvailability();
44      }
45  
46      public static final InsecureQuicTokenHandler INSTANCE = new InsecureQuicTokenHandler();
47  
48      @Override
49      public boolean writeToken(ByteBuf out, ByteBuf dcid, InetSocketAddress address) {
50          byte[] addr = address.getAddress().getAddress();
51          out.writeBytes(SERVER_NAME_BYTES)
52                  .writeBytes(addr)
53                  .writeBytes(dcid, dcid.readerIndex(), dcid.readableBytes());
54          return true;
55      }
56  
57      @Override
58      public int validateToken(ByteBuf token, InetSocketAddress address) {
59          final byte[] addr = address.getAddress().getAddress();
60  
61          int minLength = SERVER_NAME_BYTES.length + address.getAddress().getAddress().length;
62          if (token.readableBytes() <= SERVER_NAME_BYTES.length + addr.length) {
63              return -1;
64          }
65  
66          if (!SERVER_NAME_BUFFER.equals(token.slice(0, SERVER_NAME_BYTES.length))) {
67              return -1;
68          }
69          ByteBuf addressBuffer = Unpooled.wrappedBuffer(addr);
70          try {
71              if (!addressBuffer.equals(token.slice(SERVER_NAME_BYTES.length, addr.length))) {
72                  return -1;
73              }
74          } finally {
75              addressBuffer.release();
76          }
77          return minLength;
78      }
79  
80      @Override
81      public int maxTokenLength() {
82          return MAX_TOKEN_LEN;
83      }
84  }