libbgp  0.6
A C++ BGP Library.
bgp-open-message.cc
Go to the documentation of this file.
1 
11 #include "bgp-open-message.h"
12 #include "bgp-errcode.h"
13 #include "value-op.h"
14 #include <stdlib.h>
15 #include <arpa/inet.h>
16 
17 namespace libbgp {
18 
25 BgpOpenMessage::BgpOpenMessage(BgpLogHandler *logger, bool use_4b_asn) : BgpMessage(logger) {
26  this->type = OPEN;
27  this->version = 4;
28  this->use_4b_asn = use_4b_asn;
29 }
30 
31 BgpOpenMessage::~BgpOpenMessage() { }
32 
43 BgpOpenMessage::BgpOpenMessage(BgpLogHandler *logger, bool use_4b_asn, uint16_t my_asn, uint16_t hold_time, uint32_t bgp_id) : BgpOpenMessage(logger, use_4b_asn) {
44  this->my_asn = my_asn;
45  this->hold_time = hold_time;
46  this->bgp_id = bgp_id;
47  this->use_4b_asn = use_4b_asn;
48  if (use_4b_asn) setAsn(my_asn);
49 }
50 
61 BgpOpenMessage::BgpOpenMessage(BgpLogHandler *logger, bool use_4b_asn, uint16_t my_asn, uint16_t hold_time, const char* bgp_id) : BgpOpenMessage(logger, use_4b_asn) {
62  this->my_asn = my_asn;
63  this->hold_time = hold_time;
64  this->use_4b_asn = use_4b_asn;
65  if (use_4b_asn) setAsn(my_asn);
66  inet_pton(AF_INET, bgp_id, &(this->bgp_id));
67 }
68 
79 ssize_t BgpOpenMessage::parse(const uint8_t *from, size_t msg_sz) {
80  if (msg_sz < 10) {
81  uint8_t _err_data = msg_sz;
82  setError(E_HEADER, E_LENGTH, &_err_data, sizeof(uint8_t));
83  logger->log(ERROR, "BgpOpenMessage::parse: invalid open message size: %d.\n", msg_sz);
84  return -1;
85  }
86 
87  const uint8_t *buffer = from;
88 
89  version = getValue<uint8_t> (&buffer);
90  my_asn = ntohs(getValue<uint16_t> (&buffer));
91  hold_time = ntohs(getValue<uint16_t> (&buffer));
92  bgp_id = getValue<uint32_t> (&buffer);
93 
94  uint8_t opt_params_len = getValue<uint8_t> (&buffer);
95 
96  // size of rest of message != length of opt_param or invalid length
97  if (opt_params_len != msg_sz - 10 || (opt_params_len < 2 && opt_params_len != 0)) {
98  setError(E_OPEN, E_UNSPEC_OPEN, NULL, 0);
99  if (opt_params_len + 10 != (uint8_t) msg_sz)
100  logger->log(ERROR, "BgpOpenMessage::parse: size of rest of message (%d) != length of opt_param (%d).\n", msg_sz - 10, opt_params_len);
101  if (opt_params_len < 2)
102  logger->log(ERROR, "BgpOpenMessage::parse: opt params size < 2: %d.\n", opt_params_len);
103  return -1;
104  }
105 
106  uint8_t parsed_opt_params_len = 0;
107  uint8_t opt_params_len_left = 0;
108 
109  while ((opt_params_len_left = opt_params_len - parsed_opt_params_len) > 0) {
110  if (opt_params_len_left < 2) {
111  setError(E_OPEN, E_UNSPEC_OPEN, NULL, 0);
112  logger->log(ERROR, "BgpOpenMessage::parse: unexpected end of opt param list.\n");
113  return -1;
114  }
115 
116  uint8_t param_type = getValue<uint8_t> (&buffer);
117  uint8_t param_length = getValue<uint8_t> (&buffer);
118 
119  // param_type & param_length
120  parsed_opt_params_len += 2;
121 
122  // opt param size exceed opt_params_len
123  if (parsed_opt_params_len + param_length > opt_params_len) {
124  setError(E_OPEN, E_UNSPEC_OPEN, NULL, 0);
125  logger->log(ERROR, "BgpOpenMessage::parse: opt param size exceed opt_params_len.\n");
126  return -1;
127  }
128 
129  // not capability?
130  if (param_type != 2) {
131  setError(E_OPEN, E_OPT_PARAM, NULL, 0);
132  logger->log(ERROR, "BgpOpenMessage::parse: unknow opt param type: %d.\n", param_type);
133  return -1;
134  }
135 
136  // invalid capability field?
137  if (param_length < 2) {
138  setError(E_OPEN, E_UNSPEC_OPEN, NULL, 0);
139  logger->log(ERROR, "BgpOpenMessage::parse: invalid capability opt param length: %d.\n", param_length);
140  return -1;
141  }
142 
143  uint8_t parsed_capa_param_len = 0;
144  uint8_t capa_param_left = 0;
145 
146  while ((capa_param_left = param_length - parsed_capa_param_len) > 0) {
147  if (capa_param_left < 2) {
148  setError(E_OPEN, E_UNSPEC_OPEN, NULL, 0);
149  logger->log(ERROR, "BgpOpenMessage::parse: unexpected end of capa list.\n");
150  return -1;
151  }
152 
153  const uint8_t *capa_ptr = buffer;
154  uint8_t capa_code = getValue<uint8_t> (&buffer);
155  uint8_t capa_len = getValue<uint8_t> (&buffer);
156 
157  BgpCapability *cap = NULL;
158 
159  switch(capa_code) {
160  case ASN_4B: cap = new BgpCapability4BytesAsn(logger); break;
161  case MP_BGP: cap = new BgpCapabilityMpBgp(logger); break;
162  default: cap = new BgpCapabilityUnknow(logger); break;
163  }
164 
165  ssize_t capa_parsed_len = cap->parse(capa_ptr, capa_len + 2);
166 
167  if (capa_parsed_len < 0) {
168  forwardParseError(*cap);
169  delete cap;
170  return -1;
171  }
172 
173  if (capa_parsed_len != capa_len + 2) {
174  logger->log(FATAL, "BgpOpenMessage::parse: parsed capability length mismatch but no error reported.\n");
175  throw "bad_parse";
176  }
177 
178  capabilities.push_back(std::shared_ptr<BgpCapability> (cap));
179  parsed_capa_param_len += capa_parsed_len;
180  buffer += capa_parsed_len - 2;
181  }
182 
183  if (parsed_capa_param_len != param_length) {
184  logger->log(FATAL, "BgpOpenMessage::parse: parsed capabilities length mismatch but no error reported.\n");
185  throw "bad_parse";
186  }
187 
188  parsed_opt_params_len += parsed_capa_param_len;
189  }
190 
191  if (parsed_opt_params_len != opt_params_len) {
192  logger->log(FATAL, "BgpOpenMessage::parse: parsed opt params length mismatch but no error reported.\n");
193  throw "bad_parse";
194  }
195 
196  if ((size_t) (parsed_opt_params_len + 10) != msg_sz) {
197  logger->log(ERROR, "BgpOpenMessage::parse: buffer does not end after parsing finished.\n");
198  setError(E_OPEN, E_UNSPEC, NULL, 0);
199  return -1;
200  }
201 
202  return parsed_opt_params_len + 10;
203 }
204 
205 ssize_t BgpOpenMessage::write(uint8_t *to, size_t buf_sz) const {
206  if (buf_sz < 10) {
207  logger->log(ERROR, "BgpOpenMessage::write: buffer size too small (need 10, avaliable %d).\n", buf_sz);
208  return -1;
209  }
210 
211  uint8_t *buffer = to;
212 
213  putValue<uint8_t>(&buffer, version);
214  putValue<uint16_t>(&buffer, htons(my_asn));
215  putValue<uint16_t>(&buffer, htons(hold_time));
216  putValue<uint32_t>(&buffer, bgp_id);
217 
218  if (capabilities.size() == 0) {
219  putValue<uint8_t>(&buffer, 0);
220  return 10;
221  }
222 
223  uint8_t *params_len_ptr = buffer;
224  buffer++;
225 
226  // 3: opt_param type, capa_len, capa_code
227  if (buf_sz < 13) {
228  logger->log(ERROR, "BgpOpenMessage::write: buffer size too small.\n", buf_sz);
229  return -1;
230  }
231 
232  size_t opt_params_len = 2; // type & length
233  // opt_param type 2: capability
234  putValue<uint8_t>(&buffer, 2);
235 
236  uint8_t *param_len_ptr = buffer;
237  buffer++;
238 
239  size_t opt_param_len = 0;
240  for (const std::shared_ptr<BgpCapability> &capa : capabilities) {
241  ssize_t capa_wrt_ret = capa->write(buffer, buf_sz - opt_params_len - 10);
242  if (capa_wrt_ret < 0) {
243  return capa_wrt_ret;
244  }
245 
246  opt_param_len += capa_wrt_ret;
247  buffer += capa_wrt_ret;
248  }
249 
250  putValue<uint8_t>(&param_len_ptr, opt_param_len);
251 
252  opt_params_len += opt_param_len;
253  putValue<uint8_t>(&params_len_ptr, opt_params_len);
254 
255  return opt_params_len + 10;
256 }
257 
258 ssize_t BgpOpenMessage::doPrint(size_t indent, uint8_t **to, size_t *buf_left) const {
259  size_t written = 0;
260  written += _print(indent, to, buf_left, "OpenMessage {\n");
261 
262  indent++; {
263  written += _print(indent, to, buf_left, "Version { %d }\n", version);
264  written += _print(indent, to, buf_left, "MyAsn { %d }\n", my_asn);
265  written += _print(indent, to, buf_left, "BgpId { %s }\n", inet_ntoa(*(const struct in_addr*) &bgp_id));
266  written += _print(indent, to, buf_left, "HoldTimer { %d }\n", hold_time);
267  if (capabilities.size() == 0) written += _print(indent, to, buf_left, "Capabilities { }\n");
268  else {
269  _print(indent, to, buf_left, "Capabilities {\n");
270  indent++; {
271  for (const std::shared_ptr<BgpCapability> &capa : capabilities) {
272  ssize_t capa_written = capa->print(indent, *to, *buf_left);
273  if (capa_written < 0) return capa_written;
274  *to += capa_written;
275  *buf_left -= capa_written;
276  written += capa_written;
277  }
278  }; indent--;
279  _print(indent, to, buf_left, "}\n");
280  }
281  }; indent--;
282 
283  written += _print(indent, to, buf_left, "}\n");
284 
285  return written;
286 }
287 
296 uint32_t BgpOpenMessage::getAsn() const {
297  if (!use_4b_asn) return my_asn;
298 
299  for (const std::shared_ptr<BgpCapability> &capa : capabilities) {
300  if (capa->code == ASN_4B) {
301  const BgpCapability4BytesAsn &as4_cap = dynamic_cast<const BgpCapability4BytesAsn &>(*capa);
302  return as4_cap.my_asn;
303  }
304  }
305 
306  return my_asn;
307 }
308 
319 bool BgpOpenMessage::setAsn(uint32_t my_asn) {
320  this->my_asn = my_asn >= 0xffff ? 23456 : my_asn;
321 
322  if (!use_4b_asn) return true;
323 
324  for (std::shared_ptr<BgpCapability> &capa : capabilities) {
325  if (capa->code == ASN_4B) {
326  BgpCapability4BytesAsn &as4_cap = dynamic_cast<BgpCapability4BytesAsn &>(*capa);
327  as4_cap.my_asn = my_asn;
328  return true;
329  }
330  }
331 
332  BgpCapability4BytesAsn *as4_cap = new BgpCapability4BytesAsn(logger);
333  as4_cap->my_asn = my_asn;
334 
335  capabilities.push_back(std::shared_ptr<BgpCapability>(as4_cap));
336 
337  return true;
338 }
339 
347 bool BgpOpenMessage::hasCapability(uint8_t code) const {
348  for (const std::shared_ptr<BgpCapability> cap : capabilities) {
349  if (cap->code == code) return true;
350  }
351 
352  return false;
353 }
354 
360 const std::vector<std::shared_ptr<BgpCapability>>& BgpOpenMessage::getCapabilities() const {
361  return capabilities;
362 }
363 
371 bool BgpOpenMessage::addCapability(std::shared_ptr<BgpCapability> capability) {
372  capabilities.push_back(capability);
373  return true;
374 }
375 
376 }
ssize_t parse(const uint8_t *from, size_t msg_sz)
Parse a BGP open message body.
bool setAsn(uint32_t my_asn)
Set ASN.
The BgpOpenMessage class.
The BgpCapabilityMpBgp class.
The BgpCapabilityUnknow class.
The BgpCapability base class.
static ssize_t _print(size_t indent, uint8_t **to, size_t *buf_left, const char *format,...)
Print helper.
BgpOpenMessage(BgpLogHandler *logger, bool use_4b_asn)
Construct a new Bgp Open Message:: Bgp Open Message object.
The BgpCapability4BytesAsn class.
void log(LogLevel level, const char *format_str,...)
Log a message. Consider using LIBBGP_LOG if logging the message needs a lot of computing power...
const std::vector< std::shared_ptr< BgpCapability > > & getCapabilities() const
Get capabilities list.
The BGP open message.
The BgpMessage base class.
Definition: bgp-message.h:35
void setError(uint8_t err, uint8_t suberr, const uint8_t *data, size_t data_len)
Set the error information.
Definition: serializable.cc:61
Buffer operation helpers.
Definition: bgp-afi.h:14
The BgpLogHandler class.
ssize_t write(uint8_t *to, size_t buf_sz) const
Serialize a BGP message body.
bool hasCapability(uint8_t code) const
Check if open message has a capability.
ssize_t doPrint(size_t indent, uint8_t **to, size_t *buf_sz) const
Print implementation.
uint32_t getAsn() const
Get ASN.
BGP error codes.
void forwardParseError(const Serializable &other)
Forward error information from other Serializable object.
Definition: serializable.cc:97
bool addCapability(std::shared_ptr< BgpCapability > capability)
Add a capability.