From 8240e92c3e94ef80eb483647a701f66716ff40f6 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Wed, 7 Jun 2017 21:08:08 +0200 Subject: [PATCH] Add S5B providers --- ...ingleSocks5BytestreamTransportManager.java | 14 ++ .../JingleSocks5BytestreamTransport.java | 91 +++++++++ ...gleSocks5BytestreamTransportCandidate.java | 178 ++++++++++++++++++ .../jingle_s5b/elements/package-info.java | 22 +++ .../smackx/jingle_s5b/package-info.java | 21 +++ ...ngleSocks5BytestreamTransportProvider.java | 85 +++++++++ .../jingle_s5b/provider/package-info.java | 22 +++ .../JingleSocks5BytestreamTransportTest.java | 86 +++++++++ .../smackx/jingle/JingleInputStream.java | 2 +- 9 files changed, 520 insertions(+), 1 deletion(-) create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/JingleSocks5BytestreamTransportManager.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/JingleSocks5BytestreamTransport.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/JingleSocks5BytestreamTransportCandidate.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/package-info.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/package-info.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/provider/JingleSocks5BytestreamTransportProvider.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/provider/package-info.java create mode 100644 smack-experimental/src/test/java/org/jivesoftware/smackx/jingle_s5b/JingleSocks5BytestreamTransportTest.java diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/JingleSocks5BytestreamTransportManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/JingleSocks5BytestreamTransportManager.java new file mode 100644 index 000000000..efafe5e70 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/JingleSocks5BytestreamTransportManager.java @@ -0,0 +1,14 @@ +package org.jivesoftware.smackx.jingle_s5b; + +import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.XMPPConnection; + +/** + * Created by vanitas on 07.06.17. + */ +public class JingleSocks5BytestreamTransportManager extends Manager { + + private JingleSocks5BytestreamTransportManager(XMPPConnection connection) { + super(connection); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/JingleSocks5BytestreamTransport.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/JingleSocks5BytestreamTransport.java new file mode 100644 index 000000000..45662184e --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/JingleSocks5BytestreamTransport.java @@ -0,0 +1,91 @@ +package org.jivesoftware.smackx.jingle_s5b.elements; + +import java.util.ArrayList; +import java.util.List; + +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; +import org.jivesoftware.smackx.jingle.element.JingleContentTransport; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidate; + +/** + * Socks5Bytestream transport element. + */ +public class JingleSocks5BytestreamTransport extends JingleContentTransport { + public static final String NAMESPACE_V1 = "urn:xmpp:jingle:transports:s5b:1"; + public static final String ATTR_DSTADDR = "dstaddr"; + public static final String ATTR_MODE = "mode"; + public static final String ATTR_SID = "sid"; + + private final String streamId; + private final String dstAddr; + private final Bytestream.Mode mode; + + protected JingleSocks5BytestreamTransport(List candidates, String streamId, String dstAddr, Bytestream.Mode mode) { + super(candidates); + this.streamId = streamId; + this.dstAddr = dstAddr; + this.mode = mode; + } + + public String getStreamId() { + return streamId; + } + + public String getDestinationAddress() { + return dstAddr; + } + + public Bytestream.Mode getMode() { + return mode; + } + + @Override + public String getNamespace() { + return NAMESPACE_V1; + } + + @Override + protected void addExtraAttributes(XmlStringBuilder xml) { + xml.attribute(ATTR_DSTADDR, dstAddr); + xml.attribute(ATTR_MODE, mode.toString()); + xml.attribute(ATTR_SID, streamId); + } + + public static Builder getBuilder() { + return new Builder(); + } + + public static class Builder { + private String streamId; + private String dstAddr; + private Bytestream.Mode mode = Bytestream.Mode.tcp; + private ArrayList candidates = new ArrayList<>(); + + public Builder setStreamId(String sid) { + this.streamId = sid; + return this; + } + + public Builder setDestinationAddress(String dstAddr) { + this.dstAddr = dstAddr; + return this; + } + + public Builder setMode(Bytestream.Mode mode) { + this.mode = mode; + return this; + } + + public Builder addTransportCandidate(JingleSocks5BytestreamTransportCandidate candidate) { + this.candidates.add(candidate); + return this; + } + + public JingleSocks5BytestreamTransport build() { + StringUtils.requireNotNullOrEmpty(streamId, "sid MUST be neither null, nor empty."); + return new JingleSocks5BytestreamTransport(candidates, streamId, dstAddr, mode); + } + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/JingleSocks5BytestreamTransportCandidate.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/JingleSocks5BytestreamTransportCandidate.java new file mode 100644 index 000000000..ef5ff4fb2 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/JingleSocks5BytestreamTransportCandidate.java @@ -0,0 +1,178 @@ +package org.jivesoftware.smackx.jingle_s5b.elements; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.jivesoftware.smack.util.Objects; +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidate; +import org.jxmpp.jid.Jid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.jid.parts.Domainpart; +import org.jxmpp.stringprep.XmppStringprepException; + +/** + * Created by vanitas on 07.06.17. + */ +public class JingleSocks5BytestreamTransportCandidate extends JingleContentTransportCandidate { + + private static final Logger LOGGER = Logger.getLogger(JingleSocks5BytestreamTransportCandidate.class.getName()); + + public static final String ATTR_CID = "cid"; + public static final String ATTR_HOST = "host"; + public static final String ATTR_JID = "jid"; + public static final String ATTR_PORT = "port"; + public static final String ATTR_PRIORITY = "priority"; + public static final String ATTR_TYPE = "type"; + + private final String cid; + private final String host; + private final Jid jid; + private final int port; + private final int priority; + private final Type type; + + public JingleSocks5BytestreamTransportCandidate(String candidateId, String host, Jid jid, int port, int priority, Type type) { + this.cid = candidateId; + this.host = host; + this.jid = jid; + this.port = port; + this.priority = priority; + this.type = type; + } + + public enum Type { + assisted (120), + direct (126), + proxy (10), + tunnel (110), + ; + + private final int weight; + + public int getWeight() { + return weight; + } + + Type(int weight) { + this.weight = weight; + } + + public static Type fromString(String name) { + for (Type t : Type.values()) { + if (t.toString().equals(name)) { + return t; + } + } + throw new IllegalArgumentException("Illegal type: " + name); + } + } + + public String getCandidateId() { + return cid; + } + + public String getHost() { + return host; + } + + public Jid getJid() { + return jid; + } + + public int getPort() { + return port; + } + + public int getPriority() { + return priority; + } + + public Type getType() { + return type; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + xml.attribute(ATTR_CID, cid); + xml.attribute(ATTR_HOST, host); + xml.attribute(ATTR_JID, jid); + if (port >= 0) { + xml.attribute(ATTR_PORT, port); + } + xml.attribute(ATTR_PRIORITY, priority); + xml.optAttribute(ATTR_TYPE, type); + xml.closeElement(this); + return xml; + } + + public static Builder getBuilder() { + return new Builder(); + } + + public static class Builder { + + private String cid; + private String host; + private Jid jid; + private int port = -1; + private int priority = -1; + private Type type; + + private Builder() { + } + + public Builder setCandidateId(String cid) { + this.cid = cid; + return this; + } + + public Builder setHost(String host) { + this.host = host; + return this; + } + + public Builder setJid(String jid) throws XmppStringprepException { + LOGGER.log(Level.INFO, "setJid"); + try { + this.jid = JidCreate.from(jid); + } catch (XmppStringprepException | IllegalArgumentException e) { + this.jid = JidCreate.domainBareFrom(Domainpart.from(jid)); + } + LOGGER.log(Level.INFO, "setJid result: " + this.jid); + return this; + } + + public Builder setPort(int port) { + if (port < 0) { + throw new IllegalArgumentException("Port MUST NOT be less than 0."); + } + this.port = port; + return this; + } + + public Builder setPriority(int priority) { + if (priority < 0) { + throw new IllegalArgumentException("Priority MUST NOT be less than 0."); + } + this.priority = priority; + return this; + } + + public Builder setType(Type type) { + this.type = type; + return this; + } + + public JingleSocks5BytestreamTransportCandidate build() { + Objects.requireNonNull(cid); + Objects.requireNonNull(host); + Objects.requireNonNull(jid); + if (priority < 0) { + throw new IllegalArgumentException("Priority MUST be present and NOT less than 0."); + } + return new JingleSocks5BytestreamTransportCandidate(cid, host, jid, port, priority, type); + } + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/package-info.java new file mode 100644 index 000000000..8d3489235 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/elements/package-info.java @@ -0,0 +1,22 @@ +/** + * + * Copyright 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Smack's API for XEP-0260: Jingle SOCKS5 Bytestreams. + * Element classes. + */ +package org.jivesoftware.smackx.jingle_s5b.elements; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/package-info.java new file mode 100644 index 000000000..99239ec1f --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/package-info.java @@ -0,0 +1,21 @@ +/** + * + * Copyright 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Smack's API for XEP-0260: Jingle SOCKS5 Bytestreams. + */ +package org.jivesoftware.smackx.jingle_s5b; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/provider/JingleSocks5BytestreamTransportProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/provider/JingleSocks5BytestreamTransportProvider.java new file mode 100644 index 000000000..06a4bc0bd --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/provider/JingleSocks5BytestreamTransportProvider.java @@ -0,0 +1,85 @@ +package org.jivesoftware.smackx.jingle_s5b.provider; + +import static org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.Mode.tcp; +import static org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.Mode.udp; +import static org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransportCandidate.ATTR_CID; +import static org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransportCandidate.ATTR_HOST; +import static org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransportCandidate.ATTR_JID; +import static org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransportCandidate.ATTR_PORT; +import static org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransportCandidate.ATTR_PRIORITY; +import static org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransportCandidate.ATTR_TYPE; +import static org.xmlpull.v1.XmlPullParser.END_TAG; +import static org.xmlpull.v1.XmlPullParser.START_TAG; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.jivesoftware.smackx.jingle.element.JingleContentTransport; +import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider; +import org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransport; +import org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransportCandidate; +import org.xmlpull.v1.XmlPullParser; + +/** + * Provider for JingleSocks5BytestreamTransport elements. + */ +public class JingleSocks5BytestreamTransportProvider extends JingleContentTransportProvider { + + private static final Logger LOGGER = Logger.getLogger(JingleSocks5BytestreamTransportProvider.class.getName()); + @Override + public JingleSocks5BytestreamTransport parse(XmlPullParser parser, int initialDepth) throws Exception { + parser.next(); + String namespace = JingleSocks5BytestreamTransport.NAMESPACE_V1; + JingleSocks5BytestreamTransport.Builder builder = JingleSocks5BytestreamTransport.getBuilder(); + + int count = parser.getAttributeCount(); + for (int i = 0; i < count; i++) { + LOGGER.log(Level.INFO, i + " " + parser.getNamespace() + " " + parser.getAttributeName(i)); + LOGGER.log(Level.INFO, parser.getAttributeValue(parser.getNamespace(), parser.getAttributeName(i))); + } + String streamId = parser.getAttributeValue(null, JingleSocks5BytestreamTransport.ATTR_SID); + LOGGER.log(Level.INFO, "streamId: " + streamId); + builder.setStreamId(streamId); + + String dstAddr = parser.getAttributeValue(namespace, JingleSocks5BytestreamTransport.ATTR_DSTADDR); + LOGGER.log(Level.INFO, "dstAddr: " + dstAddr); + builder.setDestinationAddress(dstAddr); + + String mode = parser.getAttributeValue(namespace, JingleSocks5BytestreamTransport.ATTR_MODE); + LOGGER.log(Level.INFO, "Mode: " + mode); + if (mode != null) { + builder.setMode(mode.equals(udp.toString()) ? udp : tcp); + } + + JingleSocks5BytestreamTransportCandidate.Builder cb = null; + while (true) { + int tag = parser.nextTag(); + String name = parser.getName(); + if (tag == START_TAG && name.equals(JingleSocks5BytestreamTransportCandidate.ELEMENT)) { + LOGGER.log(Level.SEVERE, "Payload"); + cb = JingleSocks5BytestreamTransportCandidate.getBuilder(); + cb.setCandidateId(parser.getAttributeValue(null, ATTR_CID)); + cb.setHost(parser.getAttributeValue(null, ATTR_HOST)); + cb.setJid(parser.getAttributeValue(null, ATTR_JID)); + cb.setPriority(Integer.parseInt(parser.getAttributeValue(null, ATTR_PRIORITY))); + + String portString = parser.getAttributeValue(null, ATTR_PORT); + if (portString != null) { + cb.setPort(Integer.parseInt(portString)); + } + + String typeString = parser.getAttributeValue(null, ATTR_TYPE); + if (typeString != null) { + cb.setType(JingleSocks5BytestreamTransportCandidate.Type.fromString(typeString)); + } + builder.addTransportCandidate(cb.build()); + } + + if (tag == END_TAG && name.equals(JingleContentTransport.ELEMENT)) { + break; + } + } + + return builder.build(); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/provider/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/provider/package-info.java new file mode 100644 index 000000000..bdfbeaab2 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_s5b/provider/package-info.java @@ -0,0 +1,22 @@ +/** + * + * Copyright 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Smack's API for XEP-0260: Jingle SOCKS5 Bytestreams. + * Provider classes. + */ +package org.jivesoftware.smackx.jingle_s5b.provider; diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/jingle_s5b/JingleSocks5BytestreamTransportTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/jingle_s5b/JingleSocks5BytestreamTransportTest.java new file mode 100644 index 000000000..ff426a949 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/jingle_s5b/JingleSocks5BytestreamTransportTest.java @@ -0,0 +1,86 @@ +package org.jivesoftware.smackx.jingle_s5b; + +import static org.junit.Assert.assertEquals; + +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smack.test.util.TestUtils; +import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; +import org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransport; +import org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransportCandidate; +import org.jivesoftware.smackx.jingle_s5b.provider.JingleSocks5BytestreamTransportProvider; +import org.junit.Test; +import org.jxmpp.jid.impl.JidCreate; + +/** + * Test Provider and serialization. + */ +public class JingleSocks5BytestreamTransportTest extends SmackTestSuite { + + @Test + public void providerTest() throws Exception { + String xml = + "" + + + "" + + + "" + + + "" + + + ""; + JingleSocks5BytestreamTransport transport = new JingleSocks5BytestreamTransportProvider().parse(TestUtils.getParser(xml)); + assertEquals("972b7bf47291ca609517f67f86b5081086052dad", transport.getDestinationAddress()); + assertEquals("vj3hs98y", transport.getStreamId()); + assertEquals(Bytestream.Mode.tcp, transport.getMode()); + assertEquals(3, transport.getCandidates().size()); + + JingleSocks5BytestreamTransportCandidate candidate1 = + (JingleSocks5BytestreamTransportCandidate) transport.getCandidates().get(0); + assertEquals("hft54dqy", candidate1.getCandidateId()); + assertEquals("192.168.4.1", candidate1.getHost()); + assertEquals(JidCreate.from("romeo@montague.lit/orchard"), candidate1.getJid()); + assertEquals(5086, candidate1.getPort()); + assertEquals(8257636, candidate1.getPriority()); + assertEquals(JingleSocks5BytestreamTransportCandidate.Type.direct, candidate1.getType()); + + JingleSocks5BytestreamTransportCandidate candidate2 = + (JingleSocks5BytestreamTransportCandidate) transport.getCandidates().get(1); + assertEquals("hutr46fe", candidate2.getCandidateId()); + assertEquals("24.24.24.1", candidate2.getHost()); + assertEquals(JidCreate.from("romeo@montague.lit/orchard"), candidate2.getJid()); + assertEquals(5087, candidate2.getPort()); + assertEquals(8258636, candidate2.getPriority()); + assertEquals(JingleSocks5BytestreamTransportCandidate.Type.direct, candidate2.getType()); + + JingleSocks5BytestreamTransportCandidate candidate3 = + (JingleSocks5BytestreamTransportCandidate) transport.getCandidates().get(2); + assertEquals("xmdh4b7i", candidate3.getCandidateId()); + assertEquals("123.456.7.8", candidate3.getHost()); + assertEquals(JidCreate.domainBareFrom("streamer.shakespeare.lit"), candidate3.getJid()); + assertEquals(7625, candidate3.getPort()); + assertEquals(7878787, candidate3.getPriority()); + assertEquals(JingleSocks5BytestreamTransportCandidate.Type.proxy, candidate3.getType()); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleInputStream.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleInputStream.java index 2dd00d08b..f20bda008 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleInputStream.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleInputStream.java @@ -19,7 +19,7 @@ package org.jivesoftware.smackx.jingle; import java.io.InputStream; /** - * Created by vanitas on 06.06.17. + * Wrapper object that binds together an inputStream with a blockSize. */ public class JingleInputStream { private final InputStream inputStream;