1 //  $Id$
2 // Copyright (c) 2001,2002                        RIPE NCC
3 //
4 // All Rights Reserved
5 //
6 // Permission to use, copy, modify, and distribute this software and its
7 // documentation for any purpose and without fee is hereby granted,
8 // provided that the above copyright notice appear in all copies and that
9 // both that copyright notice and this permission notice appear in
10 // supporting documentation, and that the name of the author not be
11 // used in advertising or publicity pertaining to distribution of the
12 // software without specific, written prior permission.
13 //
14 // THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 // ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
16 // AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
17 // DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
18 // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 //
21 //
22 //  Copyright (c) 1994 by the University of Southern California
23 //  All rights reserved.
24 //
25 //    Permission is hereby granted, free of charge, to any person obtaining a copy
26 //    of this software and associated documentation files (the "Software"), to deal
27 //    in the Software without restriction, including without limitation the rights
28 //    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29 //    copies of the Software, and to permit persons to whom the Software is
30 //    furnished to do so, subject to the following conditions:
31 //
32 //    The above copyright notice and this permission notice shall be included in
33 //    all copies or substantial portions of the Software.
34 //
35 //    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 //    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 //    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38 //    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39 //    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40 //    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41 //    THE SOFTWARE.
42 //
43 //  Questions concerning this software should be directed to
44 //  irrtoolset@cs.usc.edu.
45 //
46 //  Author(s): Cengiz Alaettinoglu <cengiz@ISI.EDU>
47 
48 #include "config.h"
49 #include <cstdio>
50 #include "rpsl_attr.hh"
51 #include "object.hh"
52 #include "schema.hh"
53 #include <string>
54 
55 using namespace std;
56 
57 //// printing ////////////////////////////////////////////////////////
58 
print(ostream & out) const59 ostream &Attr::print(ostream &out) const {
60    if (object && object->contents)
61       out.write(object->getTextAt(offset), len);
62    return out;
63 }
64 
print(ostream & out) const65 ostream &AttrGeneric::print(ostream &out) const {
66    out << type->name() << ":\t" << *items;
67    return out;
68 }
69 
print(ostream & out) const70 ostream &AttrImport::print(ostream &out) const {
71    out << "import: ";
72    if (fromProt && fromProt->name && strcasecmp(fromProt->name, "BGP4"))
73       out << "protocol " << fromProt->name << " ";
74    if (intoProt && intoProt->name && strcasecmp(intoProt->name, "BGP4"))
75       out << "into " << intoProt->name << " ";
76    out << *policy;
77    return out;
78 }
79 
print(ostream & out) const80 ostream &AttrExport::print(ostream &out) const {
81    out << "export: ";
82    if (fromProt && fromProt->name && strcasecmp(fromProt->name, "BGP4"))
83       out << "protocol " << fromProt->name << " ";
84    if (intoProt && intoProt->name && strcasecmp(intoProt->name, "BGP4"))
85       out << "into " << intoProt->name << " ";
86    out << *policy;
87    return out;
88 }
89 
print(ostream & out) const90 ostream &AttrDefault::print(ostream &out) const {
91    out << "default: \t" << *afi_list << " to   " << *peering << "\n";
92 
93    if (!action->isEmpty())
94       out << "       \t " << *action << "\n";
95 
96    if (filter && typeid(filter) != typeid(FilterANY))
97       out << "       \t networks " << *filter;
98 
99    return out;
100 }
101 
print(ostream & out) const102 ostream &AttrFilter::print(ostream &out) const {
103    out << "filter: " << *filter;
104 
105    return out;
106 }
print(ostream & out) const107 ostream &AttrMPPeval::print(ostream &out) const {
108    out << "filter: " << *filter;
109 
110    return out;
111 }
112 
113 
print(ostream & out) const114 ostream &AttrPeering::print(ostream &out) const {
115    out << "peering: " << *peering;
116 
117    return out;
118 }
119 
print(ostream & out) const120 ostream &AttrIfAddr::print(ostream &out) const {
121 /*   static char buffer[128];
122    out << "ifaddr:\t" << int2quad(buffer, ifaddr.get_ipaddr())
123        << " masklen " << ifaddr.get_length();
124   return out;
125 */
126    out << "ifaddr/interface:\t" ;
127    out << ifaddr->get_ip_text();
128    out << " masklen " << ifaddr->get_length();
129    if (action)
130      out << " action " << *action;
131    if (tunnel)
132      out << " tunnel " << *tunnel;
133    return out;
134 }
135 
print(ostream & out) const136 ostream &AttrPeerOption::print(ostream &out) const {
137    out << option << "(" << *args << ")";
138    return out;
139 }
140 
141 /*
142 ostream &AttrPeer::print(ostream &out) const {
143    out << "peer:\t" << protocol->name
144        << " " << *peer << " ";
145    for (AttrPeerOption *nd = options->head(); nd; ) {
146       nd->print(out);
147       nd = options->next(nd);
148       if (nd)
149 	 out << ", ";
150    }
151    return out;
152 }
153 */
154 
print(ostream & out) const155 ostream &AttrPeer::print(ostream &out) const {
156    out << "peer/mp-peer:\t" << protocol->name
157        << " " << peer->get_ip_text() << " ";
158    for (AttrPeerOption *nd = options->head(); nd; ) {
159       nd->print(out);
160       nd = options->next(nd);
161       if (nd)
162    out << ", ";
163    }
164    return out;
165 }
166 
print(ostream & out) const167 ostream &AttrTypedef::print(ostream &out) const {
168    if (type)
169       out << "typedef: " << name << " " << *type;
170    else
171       out << "typedef: " << name << "<error in type spec>";
172    return out;
173 }
174 
print(ostream & out) const175 ostream &AttrProtocol::print(ostream &out) const {
176    out << "protocol: " << name;
177    for (AttrProtocolOption *nd = options->head(); nd; nd = options->next(nd)) {
178       nd->print(out);
179       out << "\n             ";
180    }
181    return out;
182 }
183 
print(ostream & out) const184 ostream &AttrProtocolOption::print(ostream &out) const {
185    out << (optional ? " optional " : " mandatory ") << *option << " ";
186    return out;
187 }
188 
print(ostream & out) const189 ostream &AttrMethod::print(ostream &out) const {
190    out << name << "(";
191    for (RPTypeNode *n = args->head(); n; ) {
192       out << *n->type;
193       n = args->next(n);
194       if (n)
195 	 out << ", ";
196    }
197    if (varargs)
198       out << ", ...";
199    out << ")";
200    return out;
201 }
202 
print(ostream & out) const203 ostream &AttrRPAttr::print(ostream &out) const {
204    out << "rp-attribute: " << name;
205    for (AttrMethod *nd = methods->head(); nd; nd = methods->next(nd))
206       out << " " << *nd;
207    return out;
208 }
209 
print(ostream & out) const210 ostream &AttrAttr::print(ostream &out) const {
211    out << "attr: " << _name << " syntax(?) ?";
212 
213    return out;
214 }
215 
216 
217 
218 
219 
220 
221 
222 
searchMethod(const char * name) const223 const AttrMethod *AttrRPAttr::searchMethod(const char *name) const {
224    char buffer[1024] = "";
225 
226    if (!isalpha(*name))
227       strcpy(buffer, "operator");
228 
229    strcat(buffer, name);
230 
231    // return method or NULL
232    for (AttrMethod *m = methods->head(); m; m = methods->next(m))
233       if (!strcasecmp(m->name, buffer))
234 	 return m;
235 
236    return NULL;
237 }
238 
searchNextMethod(const AttrMethod * last) const239 const AttrMethod *AttrRPAttr::searchNextMethod(const AttrMethod *last) const {
240    // return method or NULL
241    const AttrMethod *m = last;
242 
243    if (!last)
244       return NULL;
245 
246    for (m = methods->next(m); m; m = methods->next(m))
247       if (!strcasecmp(m->name, last->name))
248 	 return m;
249 
250    return NULL;
251 }
252 
startMandatoryCheck()253 void AttrProtocol::startMandatoryCheck() {
254    for (AttrProtocolOption *m = options->head(); m; m = options->next(m))
255       m->found = false;
256 }
257 
missingMandatoryOption()258 const AttrProtocolOption *AttrProtocol::missingMandatoryOption() {
259    AttrProtocolOption *m, *n;
260 
261    for (m = options->head(); m; m = options->next(m)) {
262       if (! m->found && ! m->optional)
263 	 return m;
264       if (m->found)
265 	 for (n = options->next(m); n; n = options->next(n))
266 	    if (!strcasecmp(m->option->name, n->option->name))
267 	       n->found = true;
268    }
269 
270    return NULL;
271 }
272 
searchOption(const char * name) const273 const AttrProtocolOption *AttrProtocol::searchOption(const char *name) const {
274    // return method or NULL
275    for (AttrProtocolOption *m = options->head(); m; m = options->next(m))
276       if (!strcasecmp(m->option->name, name)) {
277 	 m->found = true;
278 	 return m;
279       }
280 
281    return NULL;
282 }
283 
searchNextOption(const AttrProtocolOption * last) const284 const AttrProtocolOption *AttrProtocol::searchNextOption
285    (const AttrProtocolOption *last) const {
286    // return method or NULL
287    AttrProtocolOption *m = (AttrProtocolOption *) last;
288 
289    if (!last)
290       return NULL;
291 
292    for (m = options->next(m); m; m = options->next(m))
293       if (!strcasecmp(m->option->name, last->option->name)) {
294 	 m->found = true;
295 	 return m;
296       }
297 
298    return NULL;
299 }
300 
searchOption(const char * name) const301 const AttrPeerOption *AttrPeer::searchOption(const char *name) const {
302    // return method or NULL
303    for (AttrPeerOption *m = options->head(); m; m = options->next(m))
304       if (!strcasecmp(m->option, name))
305 	 return m;
306 
307    return NULL;
308 }
309 
validateArgs(ItemList * actualArgs,int & position,const RPType * & correctType) const310 bool AttrMethod::validateArgs(ItemList *actualArgs, int &position,
311 			      const RPType *&correctType) const {
312    RPTypeNode *tnode = args->head();
313    Item *arg = actualArgs->head();
314    position = 0;
315    Item *arg2;
316 
317    if (!tnode && !arg)
318       return true;
319 
320    if (!tnode)
321       return false;
322 
323    position = 1;
324    correctType = tnode->type;
325    while (correctType && arg) {
326       if (!correctType->validate(arg)) {
327 	 arg2 = correctType->typeCast(arg);
328 	 if (arg2) {
329 	    actualArgs->insertAfter(arg, arg2);
330 	    actualArgs->remove(arg);
331 	    delete arg;
332 	    arg = arg2;
333 	 } else
334 	    return false;
335       }
336 
337       position++;
338       arg = actualArgs->next(arg);
339       tnode = args->next(tnode);
340       correctType = tnode ? tnode->type : NULL;
341    }
342 
343    if (!correctType && arg && varargs) { // extra args
344       tnode = args->tail();
345       correctType = tnode->type;
346       while (correctType && arg) {
347 	 if (!correctType->validate(arg)) {
348 	    arg2 = correctType->typeCast(arg);
349 	    if (arg2) {
350 	       actualArgs->insertAfter(arg, arg2);
351 	       actualArgs->remove(arg);
352 	       delete arg;
353 	       arg = arg2;
354 	    } else
355 	       return false;
356 	 }
357 
358 	 arg = actualArgs->next(arg);
359 	 position++;
360       }
361       correctType = (RPType *) NULL;
362    }
363 
364    if (!correctType && !arg)
365       return true;
366 
367    position = 0;
368    return false;
369 }
370 
~AttrClass()371 AttrClass::~AttrClass() {
372    if (object)
373       delete object;
374    else
375       for (int i = 0; i < attribs.size(); ++i)
376 	 delete attribs[i];
377    free(name);
378 }
379 
reset()380 void AttrClass::reset() {
381    for (int i = 0; i < attribs.size(); ++i)
382       attribs[i]->reset();
383 }
384 
searchAttr(const char * name)385 AttrAttr* AttrClass::searchAttr(const char *name) {
386    for (int i = 0; i < attribs.size(); ++i)
387       if (!strcasecmp(name, attribs[i]->name())) {
388 	 attribs[i]->touch();
389 	 return attribs[i];
390       }
391 
392    return NULL;
393 }
394 
validate(std::string & errors)395 bool AttrClass::validate(std::string &errors) {
396    // return true if valid i.e. no error
397    static char buffer[1024];
398    bool result = true;
399 
400    for (int i = 0; i < attribs.size(); ++i) {
401       if (!attribs[i]->testKey()) {
402 	 sprintf(buffer, "***Error: key attribute %s is not specified.\n",
403 		 attribs[i]->name());
404 	 errors += buffer;
405 	 result = false;
406       }
407       if ((!schema.isForgiving() || attribs[i]->isKey())
408 	  && !attribs[i]->testMandatory()) {
409 	 sprintf(buffer, "***Error: mandatory attribute %s is not specified.\n",
410 		 attribs[i]->name());
411 	 errors += buffer;
412 	 result = false;
413       }
414       if ((!schema.isForgiving() || attribs[i]->isKey())
415 	  && !attribs[i]->testSingleValued()) {
416 	 sprintf(buffer,
417 		 "***Error: single-valued attribute %s occurs multiple times.\n",
418 		 attribs[i]->name());
419 	 errors += buffer;
420 	 result = false;
421       }
422    }
423    return result;
424 }
425 
print(ostream & out) const426 ostream& AttrClass::print(ostream &out) const {
427    return out;
428 }
429 
print(ostream & out) const430 ostream& AttrMntRoutes::print(ostream &out) const {
431    out << "mnt-routes:";
432    for (MntPrfxPair *p = mntPrfxList->head(); p; p = mntPrfxList->next(p)) {
433       out << " " << p->mnt;
434       if (p->prefixes)
435 	 out << " " << p->prefixes;
436       out << ",\n";
437    }
438    return out;
439 }
440 
print(ostream & out) const441 ostream& AttrTRLabel::print(ostream &out) const {
442    out << "transaction-label: "
443        << *source << " " << *seq << " " << *stamp;
444    return out;
445 }
446 
operator <<(ostream & stream,const Tunnel & p)447 ostream& operator<<(ostream& stream, const Tunnel& p) {
448    stream << p.remote_ip->get_ip_text() << " ";
449    if (p.encapsulation)
450      stream << *p.encapsulation ;
451    return stream;
452 }
453 
454