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