1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelHandlerContext;
20 import io.netty.util.CharsetUtil;
21 import io.netty.util.concurrent.Future;
22
23 import java.util.Locale;
24
25
26
27
28
29
30
31
32 public abstract class AbstractSniHandler<T> extends SslClientHelloHandler<T> {
33
34 private static String extractSniHostname(ByteBuf in) {
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 int offset = in.readerIndex();
56 int endOffset = in.writerIndex();
57 offset += 34;
58
59 if (endOffset - offset >= 6) {
60 final int sessionIdLength = in.getUnsignedByte(offset);
61 offset += sessionIdLength + 1;
62
63 final int cipherSuitesLength = in.getUnsignedShort(offset);
64 offset += cipherSuitesLength + 2;
65
66 final int compressionMethodLength = in.getUnsignedByte(offset);
67 offset += compressionMethodLength + 1;
68
69 final int extensionsLength = in.getUnsignedShort(offset);
70 offset += 2;
71 final int extensionsLimit = offset + extensionsLength;
72
73
74 if (extensionsLimit <= endOffset) {
75 while (extensionsLimit - offset >= 4) {
76 final int extensionType = in.getUnsignedShort(offset);
77 offset += 2;
78
79 final int extensionLength = in.getUnsignedShort(offset);
80 offset += 2;
81
82 if (extensionsLimit - offset < extensionLength) {
83 break;
84 }
85
86
87
88 if (extensionType == 0) {
89 offset += 2;
90 if (extensionsLimit - offset < 3) {
91 break;
92 }
93
94 final int serverNameType = in.getUnsignedByte(offset);
95 offset++;
96
97 if (serverNameType == 0) {
98 final int serverNameLength = in.getUnsignedShort(offset);
99 offset += 2;
100
101 if (extensionsLimit - offset < serverNameLength) {
102 break;
103 }
104
105 final String hostname = in.toString(offset, serverNameLength, CharsetUtil.US_ASCII);
106 return hostname.toLowerCase(Locale.US);
107 } else {
108
109 break;
110 }
111 }
112
113 offset += extensionLength;
114 }
115 }
116 }
117 return null;
118 }
119
120 private String hostname;
121
122 @Override
123 protected Future<T> lookup(ChannelHandlerContext ctx, ByteBuf clientHello) throws Exception {
124 hostname = clientHello == null ? null : extractSniHostname(clientHello);
125
126 return lookup(ctx, hostname);
127 }
128
129 @Override
130 protected void onLookupComplete(ChannelHandlerContext ctx, Future<T> future) throws Exception {
131 try {
132 onLookupComplete(ctx, hostname, future);
133 } finally {
134 fireSniCompletionEvent(ctx, hostname, future);
135 }
136 }
137
138
139
140
141
142
143
144 protected abstract Future<T> lookup(ChannelHandlerContext ctx, String hostname) throws Exception;
145
146
147
148
149
150
151 protected abstract void onLookupComplete(ChannelHandlerContext ctx,
152 String hostname, Future<T> future) throws Exception;
153
154 private static void fireSniCompletionEvent(ChannelHandlerContext ctx, String hostname, Future<?> future) {
155 Throwable cause = future.cause();
156 if (cause == null) {
157 ctx.fireUserEventTriggered(new SniCompletionEvent(hostname));
158 } else {
159 ctx.fireUserEventTriggered(new SniCompletionEvent(hostname, cause));
160 }
161 }
162 }