1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.pcap;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.ByteBufAllocator;
20 import io.netty.channel.Channel;
21 import io.netty.channel.ChannelDuplexHandler;
22 import io.netty.channel.ChannelHandlerContext;
23 import io.netty.channel.ChannelInboundHandlerAdapter;
24 import io.netty.channel.ChannelPromise;
25 import io.netty.channel.ServerChannel;
26 import io.netty.channel.socket.DatagramChannel;
27 import io.netty.channel.socket.DatagramPacket;
28 import io.netty.channel.socket.ServerSocketChannel;
29 import io.netty.channel.socket.SocketChannel;
30 import io.netty.util.NetUtil;
31 import io.netty.util.internal.logging.InternalLogger;
32 import io.netty.util.internal.logging.InternalLoggerFactory;
33
34 import java.io.Closeable;
35 import java.io.IOException;
36 import java.io.OutputStream;
37 import java.net.Inet4Address;
38 import java.net.Inet6Address;
39 import java.net.InetAddress;
40 import java.net.InetSocketAddress;
41 import java.net.UnknownHostException;
42 import java.util.concurrent.atomic.AtomicReference;
43
44 import static io.netty.util.internal.ObjectUtil.checkNotNull;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public final class PcapWriteHandler extends ChannelDuplexHandler implements Closeable {
71
72
73
74
75 private final InternalLogger logger = InternalLoggerFactory.getInstance(PcapWriteHandler.class);
76
77
78
79
80 private PcapWriter pCapWriter;
81
82
83
84
85 private final OutputStream outputStream;
86
87
88
89
90 private final boolean captureZeroByte;
91
92
93
94
95
96 private final boolean writePcapGlobalHeader;
97
98
99
100
101
102 private final boolean sharedOutputStream;
103
104
105
106
107
108 private int sendSegmentNumber = 1;
109
110
111
112
113
114 private int receiveSegmentNumber = 1;
115
116
117
118
119 private ChannelType channelType;
120
121
122
123
124 private InetSocketAddress initiatorAddr;
125
126
127
128
129 private InetSocketAddress handlerAddr;
130
131
132
133
134 private boolean isServerPipeline;
135
136
137
138
139 private final AtomicReference<State> state = new AtomicReference<State>(State.INIT);
140
141
142
143
144
145
146
147
148
149
150
151
152
153 @Deprecated
154 public PcapWriteHandler(OutputStream outputStream) {
155 this(outputStream, false, true);
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 @Deprecated
175 public PcapWriteHandler(OutputStream outputStream, boolean captureZeroByte, boolean writePcapGlobalHeader) {
176 this.outputStream = checkNotNull(outputStream, "OutputStream");
177 this.captureZeroByte = captureZeroByte;
178 this.writePcapGlobalHeader = writePcapGlobalHeader;
179 sharedOutputStream = false;
180 }
181
182 private PcapWriteHandler(Builder builder, OutputStream outputStream) {
183 this.outputStream = outputStream;
184 captureZeroByte = builder.captureZeroByte;
185 sharedOutputStream = builder.sharedOutputStream;
186 writePcapGlobalHeader = builder.writePcapGlobalHeader;
187 channelType = builder.channelType;
188 handlerAddr = builder.handlerAddr;
189 initiatorAddr = builder.initiatorAddr;
190 isServerPipeline = builder.isServerPipeline;
191 }
192
193
194
195
196
197
198
199 public static void writeGlobalHeader(OutputStream outputStream) throws IOException {
200 PcapHeaders.writeGlobalHeader(outputStream);
201 }
202
203 private void initializeIfNecessary(ChannelHandlerContext ctx) throws Exception {
204
205 if (state.get() != State.INIT) {
206 return;
207 }
208
209 pCapWriter = new PcapWriter(this);
210
211 if (channelType == null) {
212
213 if (ctx.channel() instanceof SocketChannel) {
214 channelType = ChannelType.TCP;
215
216
217
218 if (ctx.channel().parent() instanceof ServerSocketChannel) {
219 isServerPipeline = true;
220 initiatorAddr = (InetSocketAddress) ctx.channel().remoteAddress();
221 handlerAddr = getLocalAddress(ctx.channel(), initiatorAddr);
222 } else {
223 isServerPipeline = false;
224 handlerAddr = (InetSocketAddress) ctx.channel().remoteAddress();
225 initiatorAddr = getLocalAddress(ctx.channel(), handlerAddr);
226 }
227 } else if (ctx.channel() instanceof DatagramChannel) {
228 channelType = ChannelType.UDP;
229
230 DatagramChannel datagramChannel = (DatagramChannel) ctx.channel();
231
232
233
234 if (datagramChannel.isConnected()) {
235 handlerAddr = (InetSocketAddress) ctx.channel().remoteAddress();
236 initiatorAddr = getLocalAddress(ctx.channel(), handlerAddr);
237 }
238 }
239 }
240
241 if (channelType == ChannelType.TCP) {
242 logger.debug("Initiating Fake TCP 3-Way Handshake");
243
244 ByteBuf tcpBuf = ctx.alloc().buffer();
245
246 try {
247
248 TCPPacket.writePacket(tcpBuf, null, 0, 0,
249 initiatorAddr.getPort(), handlerAddr.getPort(), TCPPacket.TCPFlag.SYN);
250 completeTCPWrite(initiatorAddr, handlerAddr, tcpBuf, ctx.alloc(), ctx);
251
252
253 TCPPacket.writePacket(tcpBuf, null, 0, 1,
254 handlerAddr.getPort(), initiatorAddr.getPort(), TCPPacket.TCPFlag.SYN, TCPPacket.TCPFlag.ACK);
255 completeTCPWrite(handlerAddr, initiatorAddr, tcpBuf, ctx.alloc(), ctx);
256
257
258 TCPPacket.writePacket(tcpBuf, null, 1, 1, initiatorAddr.getPort(),
259 handlerAddr.getPort(), TCPPacket.TCPFlag.ACK);
260 completeTCPWrite(initiatorAddr, handlerAddr, tcpBuf, ctx.alloc(), ctx);
261 } finally {
262 tcpBuf.release();
263 }
264
265 logger.debug("Finished Fake TCP 3-Way Handshake");
266 }
267
268 state.set(State.WRITING);
269 }
270
271 @Override
272 public void channelActive(ChannelHandlerContext ctx) throws Exception {
273 initializeIfNecessary(ctx);
274 super.channelActive(ctx);
275 }
276
277 @Override
278 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
279
280 if (state.get() == State.INIT) {
281 initializeIfNecessary(ctx);
282 }
283
284
285 if (state.get() == State.WRITING) {
286 if (channelType == ChannelType.TCP) {
287 handleTCP(ctx, msg, false);
288 } else if (channelType == ChannelType.UDP) {
289 handleUDP(ctx, msg);
290 } else {
291 logDiscard();
292 }
293 }
294 super.channelRead(ctx, msg);
295 }
296
297 @Override
298 public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
299
300 if (state.get() == State.INIT) {
301 initializeIfNecessary(ctx);
302 }
303
304
305 if (state.get() == State.WRITING) {
306 if (channelType == ChannelType.TCP) {
307 handleTCP(ctx, msg, true);
308 } else if (channelType == ChannelType.UDP) {
309 handleUDP(ctx, msg);
310 } else {
311 logDiscard();
312 }
313 }
314 super.write(ctx, msg, promise);
315 }
316
317
318
319
320
321
322
323
324
325
326 private void handleTCP(ChannelHandlerContext ctx, Object msg, boolean isWriteOperation) {
327 if (msg instanceof ByteBuf) {
328
329
330 if (((ByteBuf) msg).readableBytes() == 0 && !captureZeroByte) {
331 logger.debug("Discarding Zero Byte TCP Packet. isWriteOperation {}", isWriteOperation);
332 return;
333 }
334
335 ByteBufAllocator byteBufAllocator = ctx.alloc();
336 ByteBuf packet = ((ByteBuf) msg).duplicate();
337 ByteBuf tcpBuf = byteBufAllocator.buffer();
338 int bytes = packet.readableBytes();
339
340 try {
341 if (isWriteOperation) {
342 final InetSocketAddress srcAddr;
343 final InetSocketAddress dstAddr;
344 if (isServerPipeline) {
345 srcAddr = handlerAddr;
346 dstAddr = initiatorAddr;
347 } else {
348 srcAddr = initiatorAddr;
349 dstAddr = handlerAddr;
350 }
351
352 TCPPacket.writePacket(tcpBuf, packet, sendSegmentNumber, receiveSegmentNumber, srcAddr.getPort(),
353 dstAddr.getPort(), TCPPacket.TCPFlag.ACK);
354 completeTCPWrite(srcAddr, dstAddr, tcpBuf, byteBufAllocator, ctx);
355 logTCP(true, bytes, sendSegmentNumber, receiveSegmentNumber, srcAddr, dstAddr, false);
356
357 sendSegmentNumber += bytes;
358
359 TCPPacket.writePacket(tcpBuf, null, receiveSegmentNumber, sendSegmentNumber, dstAddr.getPort(),
360 srcAddr.getPort(), TCPPacket.TCPFlag.ACK);
361 completeTCPWrite(dstAddr, srcAddr, tcpBuf, byteBufAllocator, ctx);
362 logTCP(true, bytes, sendSegmentNumber, receiveSegmentNumber, dstAddr, srcAddr, true);
363 } else {
364 final InetSocketAddress srcAddr;
365 final InetSocketAddress dstAddr;
366 if (isServerPipeline) {
367 srcAddr = initiatorAddr;
368 dstAddr = handlerAddr;
369 } else {
370 srcAddr = handlerAddr;
371 dstAddr = initiatorAddr;
372 }
373
374 TCPPacket.writePacket(tcpBuf, packet, receiveSegmentNumber, sendSegmentNumber, srcAddr.getPort(),
375 dstAddr.getPort(), TCPPacket.TCPFlag.ACK);
376 completeTCPWrite(srcAddr, dstAddr, tcpBuf, byteBufAllocator, ctx);
377 logTCP(false, bytes, receiveSegmentNumber, sendSegmentNumber, srcAddr, dstAddr, false);
378
379 receiveSegmentNumber += bytes;
380
381 TCPPacket.writePacket(tcpBuf, null, sendSegmentNumber, receiveSegmentNumber, dstAddr.getPort(),
382 srcAddr.getPort(), TCPPacket.TCPFlag.ACK);
383 completeTCPWrite(dstAddr, srcAddr, tcpBuf, byteBufAllocator, ctx);
384 logTCP(false, bytes, sendSegmentNumber, receiveSegmentNumber, dstAddr, srcAddr, true);
385 }
386 } finally {
387 tcpBuf.release();
388 }
389 } else {
390 logger.debug("Discarding Pcap Write for TCP Object: {}", msg);
391 }
392 }
393
394
395
396
397
398
399
400
401
402
403 private void completeTCPWrite(InetSocketAddress srcAddr, InetSocketAddress dstAddr, ByteBuf tcpBuf,
404 ByteBufAllocator byteBufAllocator, ChannelHandlerContext ctx) {
405
406 ByteBuf ipBuf = byteBufAllocator.buffer();
407 ByteBuf ethernetBuf = byteBufAllocator.buffer();
408 ByteBuf pcap = byteBufAllocator.buffer();
409
410 try {
411 if (srcAddr.getAddress() instanceof Inet4Address && dstAddr.getAddress() instanceof Inet4Address) {
412 IPPacket.writeTCPv4(ipBuf, tcpBuf,
413 NetUtil.ipv4AddressToInt((Inet4Address) srcAddr.getAddress()),
414 NetUtil.ipv4AddressToInt((Inet4Address) dstAddr.getAddress()));
415
416 EthernetPacket.writeIPv4(ethernetBuf, ipBuf);
417 } else if (srcAddr.getAddress() instanceof Inet6Address && dstAddr.getAddress() instanceof Inet6Address) {
418 IPPacket.writeTCPv6(ipBuf, tcpBuf,
419 srcAddr.getAddress().getAddress(),
420 dstAddr.getAddress().getAddress());
421
422 EthernetPacket.writeIPv6(ethernetBuf, ipBuf);
423 } else {
424 logger.error("Source and Destination IP Address versions are not same. Source Address: {}, " +
425 "Destination Address: {}", srcAddr.getAddress(), dstAddr.getAddress());
426 return;
427 }
428
429
430 pCapWriter.writePacket(pcap, ethernetBuf);
431 } catch (IOException ex) {
432 logger.error("Caught Exception While Writing Packet into Pcap", ex);
433 ctx.fireExceptionCaught(ex);
434 } finally {
435 ipBuf.release();
436 ethernetBuf.release();
437 pcap.release();
438 }
439 }
440
441
442
443
444
445
446
447
448 private void handleUDP(ChannelHandlerContext ctx, Object msg) {
449 ByteBuf udpBuf = ctx.alloc().buffer();
450
451 try {
452 if (msg instanceof DatagramPacket) {
453
454
455 if (((DatagramPacket) msg).content().readableBytes() == 0 && !captureZeroByte) {
456 logger.debug("Discarding Zero Byte UDP Packet");
457 return;
458 }
459
460 DatagramPacket datagramPacket = ((DatagramPacket) msg).duplicate();
461 InetSocketAddress srcAddr = datagramPacket.sender();
462 InetSocketAddress dstAddr = datagramPacket.recipient();
463
464
465
466 if (srcAddr == null) {
467 srcAddr = getLocalAddress(ctx.channel(), dstAddr);
468 }
469
470 logger.debug("Writing UDP Data of {} Bytes, Src Addr {}, Dst Addr {}",
471 datagramPacket.content().readableBytes(), srcAddr, dstAddr);
472
473 UDPPacket.writePacket(udpBuf, datagramPacket.content(), srcAddr.getPort(), dstAddr.getPort());
474 completeUDPWrite(srcAddr, dstAddr, udpBuf, ctx.alloc(), ctx);
475 } else if (msg instanceof ByteBuf &&
476 (!(ctx.channel() instanceof DatagramChannel) || ((DatagramChannel) ctx.channel()).isConnected())) {
477
478
479 if (((ByteBuf) msg).readableBytes() == 0 && !captureZeroByte) {
480 logger.debug("Discarding Zero Byte UDP Packet");
481 return;
482 }
483
484 ByteBuf byteBuf = ((ByteBuf) msg).duplicate();
485
486 logger.debug("Writing UDP Data of {} Bytes, Src Addr {}, Dst Addr {}",
487 byteBuf.readableBytes(), initiatorAddr, handlerAddr);
488
489 UDPPacket.writePacket(udpBuf, byteBuf, initiatorAddr.getPort(), handlerAddr.getPort());
490 completeUDPWrite(initiatorAddr, handlerAddr, udpBuf, ctx.alloc(), ctx);
491 } else {
492 logger.debug("Discarding Pcap Write for UDP Object: {}", msg);
493 }
494 } finally {
495 udpBuf.release();
496 }
497 }
498
499
500
501
502
503
504
505
506
507
508 private void completeUDPWrite(InetSocketAddress srcAddr, InetSocketAddress dstAddr, ByteBuf udpBuf,
509 ByteBufAllocator byteBufAllocator, ChannelHandlerContext ctx) {
510
511 ByteBuf ipBuf = byteBufAllocator.buffer();
512 ByteBuf ethernetBuf = byteBufAllocator.buffer();
513 ByteBuf pcap = byteBufAllocator.buffer();
514
515 try {
516 if (srcAddr.getAddress() instanceof Inet4Address && dstAddr.getAddress() instanceof Inet4Address) {
517 IPPacket.writeUDPv4(ipBuf, udpBuf,
518 NetUtil.ipv4AddressToInt((Inet4Address) srcAddr.getAddress()),
519 NetUtil.ipv4AddressToInt((Inet4Address) dstAddr.getAddress()));
520
521 EthernetPacket.writeIPv4(ethernetBuf, ipBuf);
522 } else if (srcAddr.getAddress() instanceof Inet6Address && dstAddr.getAddress() instanceof Inet6Address) {
523 IPPacket.writeUDPv6(ipBuf, udpBuf,
524 srcAddr.getAddress().getAddress(),
525 dstAddr.getAddress().getAddress());
526
527 EthernetPacket.writeIPv6(ethernetBuf, ipBuf);
528 } else {
529 logger.error("Source and Destination IP Address versions are not same. Source Address: {}, " +
530 "Destination Address: {}", srcAddr.getAddress(), dstAddr.getAddress());
531 return;
532 }
533
534
535 pCapWriter.writePacket(pcap, ethernetBuf);
536 } catch (IOException ex) {
537 logger.error("Caught Exception While Writing Packet into Pcap", ex);
538 ctx.fireExceptionCaught(ex);
539 } finally {
540 ipBuf.release();
541 ethernetBuf.release();
542 pcap.release();
543 }
544 }
545
546
547
548
549
550
551
552
553
554
555 private static InetSocketAddress getLocalAddress(Channel ch, InetSocketAddress remote) {
556 InetSocketAddress local = (InetSocketAddress) ch.localAddress();
557 if (remote != null && local.getAddress().isAnyLocalAddress()) {
558 if (local.getAddress() instanceof Inet4Address && remote.getAddress() instanceof Inet6Address) {
559 return new InetSocketAddress(WildcardAddressHolder.wildcard6, local.getPort());
560 }
561 if (local.getAddress() instanceof Inet6Address && remote.getAddress() instanceof Inet4Address) {
562 return new InetSocketAddress(WildcardAddressHolder.wildcard4, local.getPort());
563 }
564 }
565 return local;
566 }
567
568 @Override
569 public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
570
571
572 if (channelType == ChannelType.TCP) {
573 logger.debug("Starting Fake TCP FIN+ACK Flow to close connection");
574
575 ByteBufAllocator byteBufAllocator = ctx.alloc();
576 ByteBuf tcpBuf = byteBufAllocator.buffer();
577
578 try {
579
580 TCPPacket.writePacket(tcpBuf, null, sendSegmentNumber, receiveSegmentNumber, initiatorAddr.getPort(),
581 handlerAddr.getPort(), TCPPacket.TCPFlag.FIN, TCPPacket.TCPFlag.ACK);
582 completeTCPWrite(initiatorAddr, handlerAddr, tcpBuf, byteBufAllocator, ctx);
583
584
585 TCPPacket.writePacket(tcpBuf, null, receiveSegmentNumber, sendSegmentNumber, handlerAddr.getPort(),
586 initiatorAddr.getPort(), TCPPacket.TCPFlag.FIN, TCPPacket.TCPFlag.ACK);
587 completeTCPWrite(handlerAddr, initiatorAddr, tcpBuf, byteBufAllocator, ctx);
588
589
590 TCPPacket.writePacket(tcpBuf, null, sendSegmentNumber + 1, receiveSegmentNumber + 1,
591 initiatorAddr.getPort(), handlerAddr.getPort(), TCPPacket.TCPFlag.ACK);
592 completeTCPWrite(initiatorAddr, handlerAddr, tcpBuf, byteBufAllocator, ctx);
593 } finally {
594 tcpBuf.release();
595 }
596
597 logger.debug("Finished Fake TCP FIN+ACK Flow to close connection");
598 }
599
600 close();
601 super.handlerRemoved(ctx);
602 }
603
604 @Override
605 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
606
607 if (channelType == ChannelType.TCP) {
608 ByteBuf tcpBuf = ctx.alloc().buffer();
609
610 try {
611
612 TCPPacket.writePacket(tcpBuf, null, sendSegmentNumber, receiveSegmentNumber, initiatorAddr.getPort(),
613 handlerAddr.getPort(), TCPPacket.TCPFlag.RST, TCPPacket.TCPFlag.ACK);
614 completeTCPWrite(initiatorAddr, handlerAddr, tcpBuf, ctx.alloc(), ctx);
615 } finally {
616 tcpBuf.release();
617 }
618
619 logger.debug("Sent Fake TCP RST to close connection");
620 }
621
622 close();
623 ctx.fireExceptionCaught(cause);
624 }
625
626
627
628
629 private void logTCP(boolean isWriteOperation, int bytes, int sendSegmentNumber, int receiveSegmentNumber,
630 InetSocketAddress srcAddr, InetSocketAddress dstAddr, boolean ackOnly) {
631
632
633 if (logger.isDebugEnabled()) {
634 if (ackOnly) {
635 logger.debug("Writing TCP ACK, isWriteOperation {}, Segment Number {}, Ack Number {}, Src Addr {}, "
636 + "Dst Addr {}", isWriteOperation, sendSegmentNumber, receiveSegmentNumber, dstAddr, srcAddr);
637 } else {
638 logger.debug("Writing TCP Data of {} Bytes, isWriteOperation {}, Segment Number {}, Ack Number {}, " +
639 "Src Addr {}, Dst Addr {}", bytes, isWriteOperation, sendSegmentNumber,
640 receiveSegmentNumber, srcAddr, dstAddr);
641 }
642 }
643 }
644
645 OutputStream outputStream() {
646 return outputStream;
647 }
648
649 boolean sharedOutputStream() {
650 return sharedOutputStream;
651 }
652
653 boolean writePcapGlobalHeader() {
654 return writePcapGlobalHeader;
655 }
656
657
658
659
660
661 public boolean isWriting() {
662 return state.get() == State.WRITING;
663 }
664
665 State state() {
666 return state.get();
667 }
668
669
670
671
672 public void pause() {
673 if (!state.compareAndSet(State.WRITING, State.PAUSED)) {
674 throw new IllegalStateException("State must be 'STARTED' to pause but current state is: " + state);
675 }
676 }
677
678
679
680
681 public void resume() {
682 if (!state.compareAndSet(State.PAUSED, State.WRITING)) {
683 throw new IllegalStateException("State must be 'PAUSED' to resume but current state is: " + state);
684 }
685 }
686
687 void markClosed() {
688 if (state.get() != State.CLOSED) {
689 state.set(State.CLOSED);
690 }
691 }
692
693
694 PcapWriter pCapWriter() {
695 return pCapWriter;
696 }
697
698 private void logDiscard() {
699 logger.warn("Discarding pcap write because channel type is unknown. The channel this handler is registered " +
700 "on is not a SocketChannel or DatagramChannel, so the inference does not work. Please call " +
701 "forceTcpChannel or forceUdpChannel before registering the handler.");
702 }
703
704 @Override
705 public String toString() {
706 return "PcapWriteHandler{" +
707 "captureZeroByte=" + captureZeroByte +
708 ", writePcapGlobalHeader=" + writePcapGlobalHeader +
709 ", sharedOutputStream=" + sharedOutputStream +
710 ", sendSegmentNumber=" + sendSegmentNumber +
711 ", receiveSegmentNumber=" + receiveSegmentNumber +
712 ", channelType=" + channelType +
713 ", initiatorAddr=" + initiatorAddr +
714 ", handlerAddr=" + handlerAddr +
715 ", isServerPipeline=" + isServerPipeline +
716 ", state=" + state +
717 '}';
718 }
719
720
721
722
723
724
725
726
727 @Override
728 public void close() throws IOException {
729 if (state.get() == State.CLOSED) {
730 logger.debug("PcapWriterHandler is already closed");
731 } else {
732 pCapWriter.close();
733 markClosed();
734 logger.debug("PcapWriterHandler is now closed");
735 }
736 }
737
738 private enum ChannelType {
739 TCP, UDP
740 }
741
742 public static Builder builder() {
743 return new Builder();
744 }
745
746
747
748
749 public static final class Builder {
750 private boolean captureZeroByte;
751 private boolean sharedOutputStream;
752 private boolean writePcapGlobalHeader = true;
753
754 private ChannelType channelType;
755 private InetSocketAddress initiatorAddr;
756 private InetSocketAddress handlerAddr;
757 private boolean isServerPipeline;
758
759 private Builder() {
760 }
761
762
763
764
765
766
767
768
769 public Builder captureZeroByte(boolean captureZeroByte) {
770 this.captureZeroByte = captureZeroByte;
771 return this;
772 }
773
774
775
776
777
778
779
780
781
782
783
784
785 public Builder sharedOutputStream(boolean sharedOutputStream) {
786 this.sharedOutputStream = sharedOutputStream;
787 return this;
788 }
789
790
791
792
793
794
795
796
797
798 public Builder writePcapGlobalHeader(boolean writePcapGlobalHeader) {
799 this.writePcapGlobalHeader = writePcapGlobalHeader;
800 return this;
801 }
802
803
804
805
806
807
808
809
810
811
812 public Builder forceTcpChannel(InetSocketAddress serverAddress, InetSocketAddress clientAddress,
813 boolean isServerPipeline) {
814 channelType = ChannelType.TCP;
815 handlerAddr = checkNotNull(serverAddress, "serverAddress");
816 initiatorAddr = checkNotNull(clientAddress, "clientAddress");
817 this.isServerPipeline = isServerPipeline;
818 return this;
819 }
820
821
822
823
824
825
826
827
828
829
830
831
832 public Builder forceUdpChannel(InetSocketAddress localAddress, InetSocketAddress remoteAddress) {
833 channelType = ChannelType.UDP;
834 handlerAddr = checkNotNull(remoteAddress, "remoteAddress");
835 initiatorAddr = checkNotNull(localAddress, "localAddress");
836 return this;
837 }
838
839
840
841
842
843
844
845 public PcapWriteHandler build(OutputStream outputStream) {
846 checkNotNull(outputStream, "outputStream");
847 return new PcapWriteHandler(this, outputStream);
848 }
849 }
850
851 private static final class WildcardAddressHolder {
852 static final InetAddress wildcard4;
853 static final InetAddress wildcard6;
854
855 static {
856 try {
857 wildcard4 = InetAddress.getByAddress(new byte[4]);
858 wildcard6 = InetAddress.getByAddress(new byte[16]);
859 } catch (UnknownHostException e) {
860
861 throw new AssertionError(e);
862 }
863 }
864 }
865 }