Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "xmpp/xmpp_proto.h"
6 : #include <iostream>
7 : #include <string>
8 : #include <boost/algorithm/string/replace.hpp>
9 : #include <boost/algorithm/string/predicate.hpp>
10 :
11 : #include "xmpp/xmpp_connection.h"
12 : #include "xmpp/xmpp_log.h"
13 : #include "xmpp/xmpp_session.h"
14 : #include "xmpp/xmpp_str.h"
15 :
16 : #include "sandesh/sandesh_trace.h"
17 : #include "sandesh/common/vns_types.h"
18 : #include "sandesh/common/vns_constants.h"
19 : #include "sandesh/xmpp_message_sandesh_types.h"
20 : #include "sandesh/xmpp_trace_sandesh_types.h"
21 :
22 : using namespace std;
23 :
24 : unique_ptr<XmlBase> XmppProto::open_doc_(AllocXmppXmlImpl(sXMPP_STREAM_OPEN));
25 :
26 0 : XmppStanza::XmppStanza() {
27 0 : }
28 :
29 0 : XmppProto::XmppProto() {
30 0 : }
31 :
32 0 : XmppProto::~XmppProto() {
33 0 : }
34 :
35 20335 : int XmppProto::EncodeStream(const XmppStreamMessage &str, string &to,
36 : string &from, const string &xmlns, uint8_t *buf,
37 : size_t size) {
38 20335 : int len = 0;
39 :
40 20335 : switch (str.strmtype) {
41 8064 : case (XmppStanza::XmppStreamMessage::INIT_STREAM_HEADER):
42 8064 : len = EncodeOpen(buf, to, from, xmlns, size);
43 8064 : break;
44 7823 : case (XmppStanza::XmppStreamMessage::INIT_STREAM_HEADER_RESP):
45 7823 : len = EncodeOpenResp(buf, to, from, size);
46 7823 : break;
47 4448 : case (XmppStanza::XmppStreamMessage::FEATURE_TLS):
48 4448 : switch (str.strmtlstype) {
49 1513 : case (XmppStanza::XmppStreamMessage::TLS_FEATURE_REQUEST):
50 1513 : len = EncodeFeatureTlsRequest(buf);
51 1513 : break;
52 1470 : case (XmppStanza::XmppStreamMessage::TLS_START):
53 1470 : len = EncodeFeatureTlsStart(buf);
54 1470 : break;
55 1465 : case (XmppStanza::XmppStreamMessage::TLS_PROCEED):
56 1465 : len = EncodeFeatureTlsProceed(buf);
57 1465 : break;
58 : }
59 4448 : break;
60 0 : default:
61 0 : break;
62 : }
63 :
64 20335 : return len;
65 : }
66 :
67 6447 : int XmppProto::EncodeStream(const XmppStanza::XmppMessage &str, uint8_t *buf,
68 : size_t size) {
69 6447 : int ret = 0;
70 :
71 6447 : if (str.type == XmppStanza::WHITESPACE_MESSAGE_STANZA) {
72 6447 : return EncodeWhitespace(buf);
73 : }
74 :
75 0 : return ret;
76 : }
77 :
78 0 : int XmppProto::EncodeMessage(XmlBase *dom, uint8_t *buf, size_t size) {
79 0 : int len = dom->WriteDoc(buf);
80 :
81 0 : return len;
82 : }
83 :
84 0 : int XmppProto::EncodePresence(uint8_t *buf, size_t size) {
85 0 : return 0;
86 : }
87 :
88 0 : int XmppProto::EncodeIq(const XmppStanza::XmppMessageIq *iq,
89 : XmlBase *doc, uint8_t *buf, size_t size) {
90 0 : unique_ptr<XmlBase> send_doc_(AllocXmppXmlImpl());
91 :
92 : // create
93 0 : send_doc_->LoadDoc("");
94 0 : send_doc_->AddNode("iq", "");
95 :
96 0 : switch(iq->stype) {
97 0 : case XmppStanza::XmppMessageIq::GET:
98 0 : send_doc_->AddAttribute("type", "get");
99 0 : break;
100 0 : case XmppStanza::XmppMessageIq::SET:
101 0 : send_doc_->AddAttribute("type", "set");
102 0 : break;
103 0 : case XmppStanza::XmppMessageIq::RESULT:
104 0 : send_doc_->AddAttribute("type", "result");
105 0 : break;
106 0 : case XmppStanza::XmppMessageIq::ERROR:
107 0 : send_doc_->AddAttribute("type", "error");
108 0 : break;
109 0 : default:
110 0 : break;
111 : }
112 0 : send_doc_->AddAttribute("from", iq->from);
113 0 : send_doc_->AddAttribute("to", iq->to);
114 0 : send_doc_->AddAttribute("id", "id1");
115 :
116 0 : send_doc_->AddChildNode("pubsub", "");
117 0 : send_doc_->AddAttribute("xmlns", "http://jabber.org/protocol/pubsub");
118 :
119 0 : send_doc_->AppendDoc("pubsub", doc);
120 :
121 : //Returns byte encoded in the doc
122 0 : int len = send_doc_->WriteDoc(buf);
123 :
124 0 : return len;
125 0 : }
126 :
127 6447 : int XmppProto::EncodeWhitespace(uint8_t *buf) {
128 6447 : string str(sXMPP_WHITESPACE);
129 :
130 6447 : int len = str.size();
131 6447 : if (len > 0) {
132 6447 : memcpy(buf, str.data(), len);
133 : }
134 :
135 6447 : return len;
136 6447 : }
137 :
138 7823 : int XmppProto::EncodeOpenResp(uint8_t *buf, string &to, string &from,
139 : size_t max_size) {
140 :
141 7823 : unique_ptr<XmlBase> resp_doc(XmppStanza::AllocXmppXmlImpl(sXMPP_STREAM_RESP));
142 :
143 7824 : if (resp_doc.get() == NULL) {
144 0 : return 0;
145 : }
146 :
147 7824 : SetTo(to, resp_doc.get());
148 7824 : SetFrom(from, resp_doc.get());
149 :
150 7824 : std::stringstream ss;
151 7824 : resp_doc->PrintDoc(ss);
152 7824 : std::string msg;
153 7824 : msg = ss.str();
154 7824 : size_t len = msg.size();
155 7824 : if (len > max_size) {
156 0 : LOG(ERROR, "\n (Open Confirm) size greater than max buffer size \n");
157 0 : return 0;
158 : } else {
159 7824 : boost::algorithm::ireplace_last(msg, "/", " ");
160 7824 : memcpy(buf, msg.c_str(), len);
161 7823 : return len;
162 : }
163 7823 : }
164 :
165 8064 : int XmppProto::EncodeOpen(uint8_t *buf, string &to, string &from,
166 : const string &xmlns, size_t max_size) {
167 :
168 8064 : if (open_doc_.get() == NULL) {
169 0 : return 0;
170 : }
171 :
172 8064 : SetTo(to, open_doc_.get());
173 8064 : SetFrom(from, open_doc_.get());
174 8064 : SetXmlns(xmlns, open_doc_.get());
175 :
176 : //Returns byte encoded in the doc
177 8064 : std::stringstream ss;
178 8064 : open_doc_->PrintDoc(ss);
179 8064 : std::string msg;
180 8064 : msg = ss.str();
181 8064 : size_t len = msg.size();
182 8064 : if (len > max_size) {
183 0 : LOG(ERROR, "\n (Open Message) size greater than max buffer size \n");
184 0 : return 0;
185 : } else {
186 8064 : boost::algorithm::ireplace_last(msg, "/", " ");
187 8064 : memcpy(buf, msg.c_str(), len);
188 8064 : return len;
189 : }
190 8064 : }
191 :
192 1513 : int XmppProto::EncodeFeatureTlsRequest(uint8_t *buf) {
193 1513 : unique_ptr<XmlBase> resp_doc(XmppStanza::AllocXmppXmlImpl(sXMPP_STREAM_FEATURE_TLS));
194 : //Returns byte encoded in the doc
195 1513 : int len = resp_doc->WriteDoc(buf);
196 1513 : return len;
197 1513 : }
198 :
199 1470 : int XmppProto::EncodeFeatureTlsStart(uint8_t *buf) {
200 1470 : unique_ptr<XmlBase> resp_doc(XmppStanza::AllocXmppXmlImpl(sXMPP_STREAM_START_TLS));
201 : //Returns byte encoded in the doc
202 1470 : int len = resp_doc->WriteDoc(buf);
203 1470 : return len;
204 1470 : }
205 :
206 1465 : int XmppProto::EncodeFeatureTlsProceed(uint8_t *buf) {
207 1465 : unique_ptr<XmlBase> resp_doc(XmppStanza::AllocXmppXmlImpl(sXMPP_STREAM_PROCEED_TLS));
208 : //Returns byte encoded in the doc
209 1465 : int len = resp_doc->WriteDoc(buf);
210 1465 : return len;
211 1465 : }
212 :
213 4296275 : XmppStanza::XmppMessage *XmppProto::Decode(const XmppConnection *connection,
214 : const string &ts) {
215 4296275 : XmlBase *impl = XmppStanza::AllocXmppXmlImpl();
216 4296241 : if (impl == nullptr) {
217 0 : return nullptr;
218 : }
219 :
220 4296241 : XmppStanza::XmppMessage *msg = DecodeInternal(connection, ts, impl);
221 4296306 : if (!msg) {
222 0 : return nullptr;
223 : }
224 :
225 : // transfer ownership of the dom implementation
226 4296306 : msg->dom.reset(impl);
227 :
228 4296280 : return msg;
229 : }
230 :
231 4296240 : XmppStanza::XmppMessage *XmppProto::DecodeInternal(
232 : const XmppConnection *connection, const string &ts, XmlBase *impl) {
233 4296240 : XmppStanza::XmppMessage *ret = nullptr;
234 :
235 4296240 : string ns(sXMPP_STREAM_O);
236 4296221 : string ws(sXMPP_WHITESPACE);
237 4296216 : string iq(sXMPP_IQ_KEY);
238 :
239 4296217 : if (ts.find(sXMPP_IQ) != string::npos) {
240 98566 : string ts_tmp = ts;
241 :
242 98566 : if (impl->LoadDoc(ts) == -1) {
243 0 : XMPP_WARNING(XmppIqMessageParseFail, connection->ToUVEKey(),
244 : XMPP_PEER_DIR_IN);
245 0 : assert(false);
246 : goto done;
247 : }
248 :
249 98569 : XmppStanza::XmppMessageIq *msg = new XmppStanza::XmppMessageIq;
250 98563 : impl->ReadNode(iq);
251 98564 : msg->to = XmppProto::GetTo(impl);
252 98568 : msg->from = XmppProto::GetFrom(impl);
253 98566 : msg->id = XmppProto::GetId(impl);
254 98565 : msg->iq_type = XmppProto::GetType(impl);
255 : // action is subscribe,publish,collection
256 98562 : const char *action = XmppProto::GetAction(impl, msg->iq_type);
257 98562 : if (action) {
258 98547 : msg->action = action;
259 : }
260 98562 : if (XmppProto::GetNode(impl, msg->action)) {
261 98548 : msg->node = XmppProto::GetNode(impl, msg->action);
262 : }
263 : //associate or dissociate collection node
264 98562 : if (msg->action.compare("collection") == 0) {
265 41670 : if (XmppProto::GetAsNode(impl)) {
266 27302 : msg->as_node = XmppProto::GetAsNode(impl);
267 27300 : msg->is_as_node = true;
268 14368 : } else if (XmppProto::GetDsNode(impl)) {
269 14340 : msg->as_node = XmppProto::GetDsNode(impl);
270 14339 : msg->is_as_node = false;
271 : }
272 : }
273 :
274 : //msg->dom.reset(impl);
275 :
276 98560 : ret = msg;
277 :
278 98560 : XMPP_UTDEBUG(XmppIqMessageProcess, connection->ToUVEKey(),
279 : XMPP_PEER_DIR_IN, msg->node, msg->action, msg->from,
280 : msg->to, msg->id, msg->iq_type);
281 98568 : goto done;
282 :
283 4296308 : } else if (ts.find(sXMPP_MESSAGE) != string::npos) {
284 :
285 1610075 : if (impl->LoadDoc(ts) == -1) {
286 0 : XMPP_WARNING(XmppChatMessageParseFail, connection->ToUVEKey(),
287 : XMPP_PEER_DIR_IN);
288 0 : goto done;
289 : }
290 : XmppStanza::XmppMessage *msg = new XmppStanza::XmppChatMessage(
291 1610075 : STATE_NONE);
292 1610075 : impl->ReadNode(sXMPP_MESSAGE_KEY);
293 :
294 1610075 : msg->to = XmppProto::GetTo(impl);
295 1610075 : msg->from = XmppProto::GetFrom(impl);
296 1610075 : ret = msg;
297 :
298 1610075 : XMPP_UTDEBUG(XmppChatMessageProcess, connection->ToUVEKey(),
299 : XMPP_PEER_DIR_IN, msg->type, msg->from, msg->to);
300 1610075 : goto done;
301 :
302 2587667 : } else if (ts.find(sXMPP_STREAM_O) != string::npos) {
303 :
304 : // ensusre stream open is at the beginning of the message
305 15734 : string ts_tmp = ts;
306 15735 : ts_tmp.erase(std::remove(ts_tmp.begin(), ts_tmp.end(), '\n'), ts_tmp.end());
307 :
308 15735 : if ((ts_tmp.compare(0, strlen(sXMPP_STREAM_START),
309 31470 : sXMPP_STREAM_START) != 0) &&
310 15735 : (ts_tmp.compare(0, strlen(sXMPP_STREAM_START_S),
311 : sXMPP_STREAM_START_S) != 0)) {
312 0 : XMPP_WARNING(XmppBadMessage, connection->ToUVEKey(),
313 : XMPP_PEER_DIR_IN,
314 : "Open message not at the beginning.", ts);
315 0 : goto done;
316 : }
317 :
318 : // check if the buf is xmpp open or response message
319 : // As end tag will be missing we need to modify the
320 : // string for stream open, else dom decoder will fail
321 15735 : boost::algorithm::replace_last(ts_tmp, ">", "/>");
322 15733 : if (impl->LoadDoc(ts_tmp) == -1) {
323 0 : XMPP_WARNING(XmppBadMessage, connection->ToUVEKey(),
324 : XMPP_PEER_DIR_IN, "Open message parse failed.", ts);
325 0 : goto done;
326 : }
327 :
328 : XmppStanza::XmppStreamMessage *strm =
329 15736 : new XmppStanza::XmppStreamMessage();
330 15734 : strm->strmtype = XmppStanza::XmppStreamMessage::INIT_STREAM_HEADER;
331 15734 : impl->ReadNode(ns);
332 15733 : strm->to = XmppProto::GetTo(impl);
333 15734 : strm->from = XmppProto::GetFrom(impl);
334 15734 : strm->xmlns = XmppProto::GetXmlns(impl);
335 :
336 15735 : ret = strm;
337 :
338 15735 : XMPP_UTDEBUG(XmppRxOpenMessage, connection->ToUVEKey(),
339 : XMPP_PEER_DIR_IN, strm->from, strm->to);
340 :
341 2587672 : } else if (ts.find(sXMPP_STREAM_NS_TLS) != string::npos) {
342 :
343 4368 : if (impl->LoadDoc(ts) == -1) {
344 0 : XMPP_WARNING(XmppBadMessage, connection->ToUVEKey(),
345 : XMPP_PEER_DIR_IN, "Stream TLS parse failed.", ts);
346 0 : goto done;
347 : }
348 :
349 : // find stream:features tls required
350 5823 : if ((ts.find(sXMPP_STREAM_FEATURES_O) != string::npos) &&
351 5824 : (ts.find(sXMPP_STREAM_STARTTLS_O) != string::npos) &&
352 1455 : (ts.find(sXMPP_REQUIRED_O) != string::npos)) {
353 :
354 : XmppStanza::XmppStreamMessage *strm =
355 1456 : new XmppStanza::XmppStreamMessage();
356 1456 : strm->strmtype = XmppStanza::XmppStreamMessage::FEATURE_TLS;
357 1456 : strm->strmtlstype = XmppStanza::XmppStreamMessage::TLS_FEATURE_REQUEST;
358 :
359 1456 : ret = strm;
360 :
361 1456 : XMPP_UTDEBUG(XmppRxStreamTlsRequired, connection->ToUVEKey(),
362 : XMPP_PEER_DIR_IN);
363 :
364 2912 : } else if (ts.find(sXMPP_STREAM_STARTTLS_O) != string::npos) {
365 : XmppStanza::XmppStreamMessage *strm =
366 1456 : new XmppStanza::XmppStreamMessage();
367 1456 : strm->strmtype = XmppStanza::XmppStreamMessage::FEATURE_TLS;
368 1456 : strm->strmtlstype = XmppStanza::XmppStreamMessage::TLS_START;
369 1456 : ret = strm;
370 :
371 1456 : XMPP_UTDEBUG(XmppRxStreamStartTls, connection->ToUVEKey(),
372 : XMPP_PEER_DIR_IN);
373 :
374 1456 : } else if (ts.find(sXMPP_STREAM_PROCEED_O) != string::npos) {
375 : XmppStanza::XmppStreamMessage *strm =
376 1456 : new XmppStanza::XmppStreamMessage();
377 1456 : strm->strmtype = XmppStanza::XmppStreamMessage::FEATURE_TLS;
378 1456 : strm->strmtlstype = XmppStanza::XmppStreamMessage::TLS_PROCEED;
379 :
380 1456 : ret = strm;
381 :
382 1456 : XMPP_UTDEBUG(XmppRxStreamProceed, connection->ToUVEKey(),
383 : XMPP_PEER_DIR_IN);
384 : }
385 4368 : goto done;
386 :
387 2567570 : } else if (ts.find_first_of(sXMPP_VALIDWS) != string::npos) {
388 :
389 : XmppStanza::XmppMessage *msg =
390 2567571 : new XmppStanza::XmppMessage(WHITESPACE_MESSAGE_STANZA);
391 2567571 : return msg;
392 : } else {
393 0 : XMPP_WARNING(XmppBadMessage, connection->ToUVEKey(),
394 : XMPP_PEER_DIR_IN, "Message not supported", ts);
395 : }
396 :
397 1728744 : done:
398 :
399 1728744 : return ret;
400 4296315 : }
401 :
402 15888 : int XmppProto::SetTo(string &to, XmlBase *doc) {
403 15888 : if (!doc) return -1;
404 :
405 15888 : string ns(sXMPP_STREAM_O);
406 15888 : doc->ReadNode(ns);
407 15888 : doc->ModifyAttribute("to", to);
408 :
409 15888 : return 0;
410 15888 : }
411 :
412 15887 : int XmppProto::SetFrom(string &from, XmlBase *doc) {
413 15887 : if (!doc) return -1;
414 :
415 15887 : string ns(sXMPP_STREAM_O);
416 15887 : doc->ReadNode(ns);
417 15887 : return doc->ModifyAttribute("from", from);
418 15887 : }
419 :
420 8064 : int XmppProto::SetXmlns(const string &xmlns, XmlBase *doc) {
421 8064 : if (!doc)
422 0 : return -1;
423 :
424 8064 : string ns(sXMPP_STREAM_O);
425 8064 : doc->ReadNode(ns);
426 8064 : return doc->ModifyAttribute("xmlns", xmlns);
427 8064 : }
428 :
429 1724335 : const char *XmppProto::GetTo(XmlBase *doc) {
430 1724335 : if (!doc) return NULL;
431 :
432 1724335 : string tmp("to");
433 1724334 : return doc->ReadAttrib(tmp);
434 1724337 : }
435 :
436 1724348 : const char *XmppProto::GetFrom(XmlBase *doc) {
437 1724348 : if (!doc) return NULL;
438 :
439 1724348 : string tmp("from");
440 1724342 : return doc->ReadAttrib(tmp);
441 1724342 : }
442 :
443 15734 : const char *XmppProto::GetXmlns(XmlBase *doc) {
444 15734 : if (!doc)
445 0 : return NULL;
446 :
447 15734 : string tmp("xmlns");
448 15732 : return doc->ReadAttrib(tmp);
449 15735 : }
450 :
451 98566 : const char *XmppProto::GetId(XmlBase *doc) {
452 98566 : if (!doc) return NULL;
453 :
454 98566 : string tmp("id");
455 98565 : return doc->ReadAttrib(tmp);
456 98563 : }
457 :
458 98565 : const char *XmppProto::GetType(XmlBase *doc) {
459 98565 : if (!doc) return NULL;
460 :
461 98565 : string tmp("type");
462 98565 : return doc->ReadAttrib(tmp);
463 98564 : }
464 :
465 98564 : const char *XmppProto::GetAction(XmlBase *doc, const string &str) {
466 98564 : if (!doc) return NULL;
467 :
468 98564 : if (str.compare("set") == 0) {
469 98553 : doc->ReadNode("pubsub");
470 98547 : return(doc->ReadChildNodeName());
471 15 : } else if (str.compare("get") == 0) {
472 : }
473 :
474 15 : return(NULL);
475 : }
476 :
477 197107 : const char *XmppProto::GetNode(XmlBase *doc, const string &str) {
478 197107 : if (!doc) return NULL;
479 :
480 197107 : if (!str.empty()) {
481 197093 : return(doc->ReadAttrib("node"));
482 : }
483 :
484 15 : return(NULL);
485 : }
486 :
487 68972 : const char *XmppProto::GetAsNode(XmlBase *doc) {
488 68972 : if (!doc) return NULL;
489 :
490 68972 : const char *node = doc->ReadNode("associate");
491 68970 : if (node != NULL) {
492 54602 : return(doc->ReadAttrib("node"));
493 : }
494 :
495 14368 : return(NULL);
496 : }
497 :
498 28708 : const char *XmppProto::GetDsNode(XmlBase *doc) {
499 28708 : if (!doc) return NULL;
500 :
501 28708 : const char *node = doc->ReadNode("dissociate");
502 28707 : if (node != NULL) {
503 28679 : return(doc->ReadAttrib("node"));
504 : }
505 :
506 28 : return(NULL);
507 : }
|