aboutsummaryrefslogtreecommitdiff
path: root/juick-xmpp/src/main/java/com/juick/components/s2s/ConnectionIn.java
diff options
context:
space:
mode:
Diffstat (limited to 'juick-xmpp/src/main/java/com/juick/components/s2s/ConnectionIn.java')
-rw-r--r--juick-xmpp/src/main/java/com/juick/components/s2s/ConnectionIn.java227
1 files changed, 227 insertions, 0 deletions
diff --git a/juick-xmpp/src/main/java/com/juick/components/s2s/ConnectionIn.java b/juick-xmpp/src/main/java/com/juick/components/s2s/ConnectionIn.java
new file mode 100644
index 00000000..41336582
--- /dev/null
+++ b/juick-xmpp/src/main/java/com/juick/components/s2s/ConnectionIn.java
@@ -0,0 +1,227 @@
+package com.juick.components.s2s;
+
+import com.juick.components.XMPPServer;
+import com.juick.xmpp.Iq;
+import com.juick.xmpp.JID;
+import com.juick.xmpp.Message;
+import com.juick.xmpp.Presence;
+import com.juick.xmpp.utils.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocket;
+import java.io.EOFException;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author ugnich
+ */
+public class ConnectionIn extends Connection implements Runnable {
+
+ private static final Logger LOGGER = Logger.getLogger(ConnectionIn.class.getName());
+
+ final public List<String> from = new ArrayList<>();
+ public long tsRemoteData = 0;
+ public long packetsRemote = 0;
+ JuickBot bot;
+
+ public ConnectionIn(XMPPServer xmpp, JuickBot bot, Socket socket) throws Exception {
+ super(xmpp);
+ this.bot = bot;
+ this.socket = socket;
+ streamID = UUID.randomUUID().toString();
+ restartParser();
+ }
+
+ @Override
+ public void run() {
+ LOGGER.info("STREAM FROM ? " + streamID + " START");
+ try {
+ parser.next(); // stream:stream
+ updateTsRemoteData();
+ if (!parser.getName().equals("stream")
+ || !parser.getNamespace("stream").equals(NS_STREAM)) {
+// || !parser.getAttributeValue(null, "version").equals("1.0")
+// || !parser.getAttributeValue(null, "to").equals(Main.HOSTNAME)) {
+ throw new Exception("STREAM FROM ? " + streamID + " INVALID FIRST PACKET");
+ }
+ boolean xmppversionnew = parser.getAttributeValue(null, "version") != null;
+ String from = parser.getAttributeValue(null, "from");
+
+ if (xmpp.bannedHosts.contains(from)) {
+ closeConnection();
+ return;
+ }
+ sendOpenStream(from, xmppversionnew);
+
+ while (parser.next() != XmlPullParser.END_DOCUMENT) {
+ updateTsRemoteData();
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ logParser();
+
+ packetsRemote++;
+
+ String tag = parser.getName();
+ if (tag.equals("result") && parser.getNamespace().equals(NS_DB)) {
+ String dfrom = parser.getAttributeValue(null, "from");
+ String to = parser.getAttributeValue(null, "to");
+ LOGGER.info("STREAM FROM " + dfrom + " TO " + to + " " + streamID + " ASKING FOR DIALBACK");
+ if (dfrom.endsWith(xmpp.HOSTNAME) && (dfrom.equals(xmpp.HOSTNAME) || dfrom.endsWith("." + xmpp.HOSTNAME))) {
+ break;
+ }
+ if (to != null && to.equals(xmpp.HOSTNAME)) {
+ String dbKey = XmlUtils.getTagText(parser);
+ updateTsRemoteData();
+
+ ConnectionOut c = xmpp.getConnectionOut(dfrom, false);
+ if (c != null) {
+ c.sendDialbackVerify(streamID, dbKey);
+ } else {
+ c = new ConnectionOut(xmpp, dfrom, streamID, dbKey);
+ xmpp.service.submit(c);
+ }
+ } else {
+ throw new HostUnknownException("STREAM FROM " + dfrom + " " + streamID + " INVALID TO " + to);
+ }
+ } else if (tag.equals("verify") && parser.getNamespace().equals(NS_DB)) {
+ String vfrom = parser.getAttributeValue(null, "from");
+ String vto = parser.getAttributeValue(null, "to");
+ String vid = parser.getAttributeValue(null, "id");
+ String vkey = XmlUtils.getTagText(parser);
+ updateTsRemoteData();
+ boolean valid = false;
+ if (vfrom != null && vto != null && vid != null && vkey != null) {
+ String vkey2 = generateDialbackKey(vfrom, vto, vid);
+ valid = vkey.equals(vkey2);
+ }
+ if (valid) {
+ sendStanza("<db:verify from='" + vto + "' to='" + vfrom + "' id='" + vid + "' type='valid'/>");
+ LOGGER.info("STREAM FROM " + vfrom + " " + streamID + " DIALBACK VERIFY VALID");
+ } else {
+ sendStanza("<db:verify from='" + vto + "' to='" + vfrom + "' id='" + vid + "' type='invalid'/>");
+ LOGGER.warning("STREAM FROM " + vfrom + " " + streamID + " DIALBACK VERIFY INVALID");
+ }
+ } else if (tag.equals("presence") && checkFromTo(parser)) {
+ Presence p = Presence.parse(parser, null);
+ if (p != null && (p.type == null || !p.type.equals(Presence.Type.error))) {
+ bot.incomingPresence(p);
+ }
+ } else if (tag.equals("message") && checkFromTo(parser)) {
+ updateTsRemoteData();
+ Message msg = Message.parse(parser, xmpp.childParsers);
+ if (msg != null && (msg.type == null || !msg.type.equals(Message.Type.error))) {
+ LOGGER.info("STREAM " + streamID + ": " + msg.toString());
+ if (!bot.incomingMessage(msg)) {
+ xmpp.getRouter().send(msg.toString());
+ }
+ }
+ } else if (tag.equals("iq") && checkFromTo(parser)) {
+ updateTsRemoteData();
+ String type = parser.getAttributeValue(null, "type");
+ String xml = XmlUtils.parseToString(parser, true);
+ if (type == null || !type.equals(Iq.Type.error)) {
+ LOGGER.info("STREAM " + streamID + ": " + xml);
+ xmpp.getRouter().send(xml);
+ }
+ } else if (sc != null && !isSecured() && tag.equals("starttls")) {
+ LOGGER.info("STREAM " + streamID + " SECURING");
+ sendStanza("<proceed xmlns=\"" + NS_TLS + "\" />");
+ try {
+ socket = sc.getSocketFactory().createSocket(socket, socket.getInetAddress().getHostAddress(),
+ socket.getPort(), true);
+ ((SSLSocket) socket).setUseClientMode(false);
+ ((SSLSocket) socket).startHandshake();
+ setSecured(true);
+ LOGGER.info("STREAM " + streamID + " SECURED");
+ restartParser();
+ } catch (SSLException sex) {
+ LOGGER.warning("STREAM " + streamID + " SSL ERROR");
+ sendStanza("<failed xmlns\"" + NS_TLS + "\" />");
+ xmpp.removeConnectionIn(this);
+ closeConnection();
+ }
+ } else if (isSecured() && tag.equals("stream") && parser.getNamespace().equals(NS_STREAM)) {
+ sendOpenStream(null, true);
+ } else {
+ LOGGER.info("STREAM " + streamID + ": " + XmlUtils.parseToString(parser, true));
+ }
+ }
+ LOGGER.warning("STREAM " + streamID + " FINISHED");
+ xmpp.removeConnectionIn(this);
+ closeConnection();
+ } catch (EOFException | SocketException ex) {
+ LOGGER.info(String.format("STREAM %s CLOSED (dirty)", streamID));
+ xmpp.removeConnectionIn(this);
+ closeConnection();
+ } catch (HostUnknownException e) {
+ LOGGER.warning(e.getMessage());
+ } catch (Exception e) {
+ LOGGER.log(Level.WARNING, "STREAM " + streamID + " ERROR", e);
+ xmpp.removeConnectionIn(this);
+ closeConnection();
+ }
+ }
+
+ void updateTsRemoteData() {
+ tsRemoteData = System.currentTimeMillis();
+ }
+
+ void sendOpenStream(String from, boolean xmppversionnew) throws IOException {
+ String openStream = "<?xml version='1.0'?><stream:stream xmlns='jabber:server' " +
+ "xmlns:stream='http://etherx.jabber.org/streams' xmlns:db='jabber:server:dialback' from='" +
+ xmpp.HOSTNAME + "' id='" + streamID + "' version='1.0'>";
+ if (xmppversionnew) {
+ openStream += "<stream:features>";
+ if (sc != null && !isSecured() && !xmpp.brokenSSLhosts.contains(from)) {
+ openStream += "<starttls xmlns=\"" + NS_TLS + "\"><optional/></starttls>";
+ }
+ openStream += "</stream:features>";
+ }
+ sendStanza(openStream);
+ }
+
+ public void sendDialbackResult(String sfrom, String type) {
+ try {
+ sendStanza("<db:result from='" + xmpp.HOSTNAME + "' to='" + sfrom + "' type='" + type + "'/>");
+ if (type.equals("valid")) {
+ from.add(sfrom);
+ LOGGER.info("STREAM FROM " + sfrom + " " + streamID + " READY");
+ }
+ } catch (IOException e) {
+ LOGGER.warning("STREAM FROM " + sfrom + " " + streamID + " ERROR: " + e.toString());
+ }
+ }
+
+ boolean checkFromTo(XmlPullParser parser) throws Exception {
+ String cfrom = parser.getAttributeValue(null, "from");
+ String cto = parser.getAttributeValue(null, "to");
+ if (cfrom != null && cto != null && !cfrom.isEmpty() && !cto.isEmpty()) {
+ JID jidto = new JID(cto);
+ if (jidto.Host != null && jidto.Username != null && jidto.Host.equals(xmpp.HOSTNAME) && jidto.Username.matches("^[a-zA-Z0-9\\-]{2,16}$")) {
+ JID jidfrom = new JID(cfrom);
+ int size = from.size();
+ for (int i = 0; i < size; i++) {
+ if (from.get(i).equals(jidfrom.Host)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ class HostUnknownException extends Exception {
+ public HostUnknownException(String message) {
+ super(message);
+ }
+ }
+}