From cf978e1531fec77b4998bc0bd583f5fb2e1cf7ea Mon Sep 17 00:00:00 2001 From: Teerapap Changwichukarn Date: Mon, 21 Aug 2023 17:51:07 +0800 Subject: [PATCH] Fix Via header builder to print IPv6 address brackets According to RFC3261, IPv6 address in host part of the Via header must be enclosed with brackets ('[' and ']') Changes in detail * Enclose the host part of Via header with brackets ('[' and ']') when it is IPv6 address * Add unit tests for IPv6 address case --- .../io/pkts/packet/sip/header/ViaHeader.java | 26 ++++++++++++- .../sip/header/impl/ViaHeaderImplTest.java | 37 +++++++++++++++---- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/pkts-sip/src/main/java/io/pkts/packet/sip/header/ViaHeader.java b/pkts-sip/src/main/java/io/pkts/packet/sip/header/ViaHeader.java index c0543eeb..84d848cf 100644 --- a/pkts-sip/src/main/java/io/pkts/packet/sip/header/ViaHeader.java +++ b/pkts-sip/src/main/java/io/pkts/packet/sip/header/ViaHeader.java @@ -530,11 +530,35 @@ public ViaHeader build() throws SipParseException { return new ViaHeaderImpl(via, transport, host, port, params, indexOfBranch, indexOfReceived, indexOfRPort); } - private void transferValue(final Buffer dst) { + private boolean isIPv6Address(final Buffer host) throws SipParseException { + host.markReaderIndex(); + try { + while (host.hasReadableBytes()) { + final byte b = host.readByte(); + if (b == SipParser.COLON) { + return true; + } + } + return false; // no colon found so it is not IPv6 address + } catch (IOException ex) { + throw new SipParseException(host.getReaderIndex(), "Fail to read host buffer", ex); + } finally { + host.resetReaderIndex(); + } + } + + private void transferValue(final Buffer dst) throws SipParseException { SipParser.SIP2_0_SLASH.getBytes(0, dst); this.transport.toUpperCaseBuffer().getBytes(0, dst); dst.write(SipParser.SP); + boolean isHostIPv6 = isIPv6Address(this.host); + if (isHostIPv6) { + dst.write(SipParser.LSBRACKET); + } this.host.getBytes(0, dst); + if (isHostIPv6) { + dst.write(SipParser.RSBRACKET); + } if (this.port != -1) { dst.write(SipParser.COLON); dst.writeAsString(this.port); diff --git a/pkts-sip/src/test/java/io/pkts/packet/sip/header/impl/ViaHeaderImplTest.java b/pkts-sip/src/test/java/io/pkts/packet/sip/header/impl/ViaHeaderImplTest.java index 392029f4..8beba0e2 100644 --- a/pkts-sip/src/test/java/io/pkts/packet/sip/header/impl/ViaHeaderImplTest.java +++ b/pkts-sip/src/test/java/io/pkts/packet/sip/header/impl/ViaHeaderImplTest.java @@ -20,15 +20,24 @@ public class ViaHeaderImplTest { @Test public void testBuildFromScratch() throws Exception { - final ViaHeader via = ViaHeader.withHost("pkts.io") - .withBranch("hello") - .withPort(5088) - .build(); + // domain name + assertViaBuild("pkts.io", 5088, "hello", "Via: SIP/2.0/UDP pkts.io:5088;branch=hello"); + + // IPv4 address + assertViaBuild("127.0.0.1", 5088, "hello", "Via: SIP/2.0/UDP 127.0.0.1:5088;branch=hello"); + + // IPv6 address + final String[] ipv6Array = new String[]{ + "2001:0db8:85a3:0042:1000:8a2e:0370:7334" /* full form */, + "ef82::1a12:1234:1b12", /* Rule 1 - zero compression rule */ + "1234:fd2:5621:1:89:0:0:4500", /* Rule 2 - leading zero compression rule */ + "2001:1234::1b12:0:0:1a13", /* Rule 3 - zero is compressed at only one junction */ + }; + + for (String ipv6 : ipv6Array) { + assertViaBuild(ipv6, 5088, "hello", "Via: SIP/2.0/UDP [" + ipv6 + "]:5088;branch=hello"); + } - assertThat(via.getPort(), is(5088)); - assertThat(via.getBranch().toString(), is("hello")); - assertThat(via.getHost().toString(), is("pkts.io")); - assertThat(via.toString(), is("Via: SIP/2.0/UDP pkts.io:5088;branch=hello")); } @Test @@ -136,6 +145,18 @@ public void testSetParam() throws Exception { } + private void assertViaBuild(String host, int port, String branch, String expectedOutput) { + final ViaHeader via = ViaHeader.withHost(host) + .withBranch(branch) + .withPort(port) + .build(); + + assertThat(via.getPort(), is(port)); + assertThat(via.getBranch().toString(), is(branch)); + assertThat(via.getHost().toString(), is(host)); + assertThat(via.toString(), is(expectedOutput)); + } + private void assertViaRport(final String toParse, final int port) throws Exception { final ViaHeader via = ViaHeader.frame(Buffers.wrap(toParse)).copy().withRPort(port).build(); assertThat(via.getRPort(), is(port));