github.com/osrg/gobgp@v2.0.0+incompatible/test/scenario_test/route_server_malformed_test.py (about)

     1  # Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #    http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  # implied.
    13  # See the License for the specific language governing permissions and
    14  # limitations under the License.
    15  
    16  from __future__ import absolute_import
    17  
    18  import sys
    19  import time
    20  import unittest
    21  import inspect
    22  
    23  from fabric.api import local
    24  import nose
    25  
    26  from lib.noseplugin import OptionParser, parser_option
    27  
    28  from lib import base
    29  from lib.base import BGP_FSM_ESTABLISHED
    30  from lib.gobgp import GoBGPContainer
    31  from lib.exabgp import ExaBGPContainer
    32  
    33  
    34  counter = 1
    35  _SCENARIOS = {}
    36  
    37  
    38  def register_scenario(cls):
    39      global counter
    40      _SCENARIOS[counter] = cls
    41      counter += 1
    42  
    43  
    44  def lookup_scenario(name):
    45      for value in _SCENARIOS.values():
    46          if value.__name__ == name:
    47              return value
    48      return None
    49  
    50  
    51  def wait_for(f, timeout=120):
    52      interval = 1
    53      count = 0
    54      while True:
    55          if f():
    56              return
    57  
    58          time.sleep(interval)
    59          count += interval
    60          if count >= timeout:
    61              raise Exception('timeout')
    62  
    63  
    64  @register_scenario
    65  class MalformedMpReachNlri(object):
    66      """
    67        No.1 malformaed mp-reach-nlri
    68      """
    69  
    70      @staticmethod
    71      def boot(env):
    72          gobgp_ctn_image_name = env.parser_option.gobgp_image
    73          log_level = env.parser_option.gobgp_log_level
    74          g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1',
    75                              ctn_image_name=gobgp_ctn_image_name,
    76                              log_level=log_level)
    77          e1 = ExaBGPContainer(name='e1', asn=65001, router_id='192.168.0.2')
    78          e2 = ExaBGPContainer(name='e2', asn=65001, router_id='192.168.0.2')
    79  
    80          ctns = [g1, e1, e2]
    81          initial_wait_time = max(ctn.run() for ctn in ctns)
    82          time.sleep(initial_wait_time)
    83  
    84          for q in [e1, e2]:
    85              g1.add_peer(q, is_rs_client=True)
    86              q.add_peer(g1)
    87  
    88          env.g1 = g1
    89          env.e1 = e1
    90          env.e2 = e2
    91  
    92      @staticmethod
    93      def setup(env):
    94          g1 = env.g1
    95          e1 = env.e1
    96          e2 = env.e2
    97          for c in [e1, e2]:
    98              g1.wait_for(BGP_FSM_ESTABLISHED, c)
    99  
   100          # advertise malformed MP_REACH_NLRI
   101          e1.add_route('10.7.0.17/32', attribute='0x0e 0x60 0x11223344')
   102  
   103      @staticmethod
   104      def check(env):
   105          g1 = env.g1
   106          e1 = env.e1
   107          e2 = env.e2
   108  
   109          def f():
   110              for line in e1.log().split('\n'):
   111                  if 'UPDATE message error / Attribute Flags Error / 0x600E0411223344' in line:
   112                      return True
   113              return False
   114  
   115          wait_for(f)
   116          # check e2 is still established
   117          g1.wait_for(BGP_FSM_ESTABLISHED, e2)
   118  
   119      @staticmethod
   120      def executor(env):
   121          lookup_scenario("MalformedMpReachNlri").boot(env)
   122          lookup_scenario("MalformedMpReachNlri").setup(env)
   123          lookup_scenario("MalformedMpReachNlri").check(env)
   124  
   125  
   126  @register_scenario
   127  class MalformedMpUnReachNlri(object):
   128      """
   129        No.2 malformaed mp-unreach-nlri
   130      """
   131  
   132      @staticmethod
   133      def boot(env):
   134          lookup_scenario("MalformedMpReachNlri").boot(env)
   135  
   136      @staticmethod
   137      def setup(env):
   138          g1 = env.g1
   139          e1 = env.e1
   140          e2 = env.e2
   141          for c in [e1, e2]:
   142              g1.wait_for(BGP_FSM_ESTABLISHED, c)
   143  
   144          # advertise malformed MP_UNREACH_NLRI
   145          e1.add_route('10.7.0.17/32', attribute='0x0f 0x60 0x11223344')
   146  
   147      @staticmethod
   148      def check(env):
   149          g1 = env.g1
   150          e1 = env.e1
   151          e2 = env.e2
   152  
   153          def f():
   154              for line in e1.log().split('\n'):
   155                  if 'UPDATE message error / Attribute Flags Error / 0x600F0411223344' in line:
   156                      return True
   157              return False
   158  
   159          wait_for(f)
   160          # check e2 is still established
   161          g1.wait_for(BGP_FSM_ESTABLISHED, e2)
   162  
   163      @staticmethod
   164      def executor(env):
   165          lookup_scenario("MalformedMpUnReachNlri").boot(env)
   166          lookup_scenario("MalformedMpUnReachNlri").setup(env)
   167          lookup_scenario("MalformedMpUnReachNlri").check(env)
   168  
   169  
   170  @register_scenario
   171  class MalformedAsPath(object):
   172      """
   173        No.3 malformaed as-path
   174      """
   175  
   176      @staticmethod
   177      def boot(env):
   178          lookup_scenario("MalformedMpReachNlri").boot(env)
   179  
   180      @staticmethod
   181      def setup(env):
   182          g1 = env.g1
   183          e1 = env.e1
   184          e2 = env.e2
   185          for c in [e1, e2]:
   186              g1.wait_for(BGP_FSM_ESTABLISHED, c)
   187  
   188          # advertise malformed AS_PATH
   189          # Send the attribute to the length and number of aspath is inconsistent
   190          # Attribute Type  0x02 (AS_PATH)
   191          # Attribute Flag  0x40 (well-known transitive)
   192          # Attribute Value 0x02020000ffdc (
   193          #  segment type    = 02
   194          #  segment length  = 02 -> # correct value = 01
   195          #  as number       = 65500   )
   196          e1.add_route('10.7.0.17/32', attribute='0x02 0x60 0x11223344')
   197  
   198      @staticmethod
   199      def check(env):
   200          g1 = env.g1
   201          e1 = env.e1
   202          e2 = env.e2
   203  
   204          def f():
   205              for line in e1.log().split('\n'):
   206                  if 'UPDATE message error / Attribute Flags Error / 0x60020411223344' in line:
   207                      return True
   208              return False
   209  
   210          wait_for(f)
   211          # check e2 is still established
   212          g1.wait_for(BGP_FSM_ESTABLISHED, e2)
   213  
   214      @staticmethod
   215      def executor(env):
   216          lookup_scenario("MalformedAsPath").boot(env)
   217          lookup_scenario("MalformedAsPath").setup(env)
   218          lookup_scenario("MalformedAsPath").check(env)
   219  
   220  
   221  @register_scenario
   222  class MalformedAs4Path(object):
   223      """
   224        No.4 malformaed as4-path
   225      """
   226  
   227      @staticmethod
   228      def boot(env):
   229          lookup_scenario("MalformedMpReachNlri").boot(env)
   230  
   231      @staticmethod
   232      def setup(env):
   233          g1 = env.g1
   234          e1 = env.e1
   235          e2 = env.e2
   236          for c in [e1, e2]:
   237              g1.wait_for(BGP_FSM_ESTABLISHED, c)
   238  
   239          # advertise malformed AS4_PATH
   240          e1.add_route('10.7.0.17/32', attribute='0x11 0x60 0x11223344')
   241  
   242      @staticmethod
   243      def check(env):
   244          g1 = env.g1
   245          e1 = env.e1
   246          e2 = env.e2
   247  
   248          def f():
   249              for line in e1.log().split('\n'):
   250                  if 'UPDATE message error / Attribute Flags Error / 0x60110411223344' in line:
   251                      return True
   252              return False
   253  
   254          wait_for(f)
   255          # check e2 is still established
   256          g1.wait_for(BGP_FSM_ESTABLISHED, e2)
   257  
   258      @staticmethod
   259      def executor(env):
   260          lookup_scenario("MalformedAs4Path").boot(env)
   261          lookup_scenario("MalformedAs4Path").setup(env)
   262          lookup_scenario("MalformedAs4Path").check(env)
   263  
   264  
   265  @register_scenario
   266  class MalformedNexthop(object):
   267      """
   268        No.5 malformaed nexthop
   269      """
   270  
   271      @staticmethod
   272      def boot(env):
   273          lookup_scenario("MalformedMpReachNlri").boot(env)
   274  
   275      @staticmethod
   276      def setup(env):
   277          g1 = env.g1
   278          e1 = env.e1
   279          e2 = env.e2
   280          for c in [e1, e2]:
   281              g1.wait_for(BGP_FSM_ESTABLISHED, c)
   282  
   283          # advertise malformed NEXT_HOP
   284          # 0x0e: MP_REACH_NLRI
   285          # 0x60: Optional, Transitive
   286          # 0x01: AFI(IPv4)
   287          # 0x01: SAFI(unicast)
   288          # 0x10: Length of Next Hop Address
   289          # 0xffffff00: Network address of Next Hop
   290          # 0x00: Reserved
   291          e1.add_route('10.7.0.17/32', attribute='0x0e 0x60 0x010110ffffff0000')
   292  
   293      @staticmethod
   294      def check(env):
   295          g1 = env.g1
   296          e1 = env.e1
   297          e2 = env.e2
   298  
   299          def f():
   300              for line in e1.log().split('\n'):
   301                  if 'UPDATE message error / Attribute Flags Error / 0x600E08010110FFFFFF0000' in line:
   302                      return True
   303              return False
   304  
   305          wait_for(f)
   306          # check e2 is still established
   307          g1.wait_for(BGP_FSM_ESTABLISHED, e2)
   308  
   309      @staticmethod
   310      def executor(env):
   311          lookup_scenario("MalformedNexthop").boot(env)
   312          lookup_scenario("MalformedNexthop").setup(env)
   313          lookup_scenario("MalformedNexthop").check(env)
   314  
   315  
   316  @register_scenario
   317  class MalformedRouteFamily(object):
   318      """
   319        No.6 malformaed route family
   320      """
   321  
   322      @staticmethod
   323      def boot(env):
   324          lookup_scenario("MalformedMpReachNlri").boot(env)
   325  
   326      @staticmethod
   327      def setup(env):
   328          g1 = env.g1
   329          e1 = env.e1
   330          e2 = env.e2
   331          for c in [e1, e2]:
   332              g1.wait_for(BGP_FSM_ESTABLISHED, c)
   333  
   334          # advertise malformed ROUTE_FAMILY
   335          # 0x0e: MP_REACH_NLRI
   336          # 0x60: Optional, Transitive
   337          # 0x01: AFI(IPv4)
   338          # 0x01: SAFI(unicast)
   339          # 0x10: Length of Next Hop Address
   340          # 0xffffff00: Network address of Next Hop
   341          # 0x00: Reserved
   342          e1.add_route('10.7.0.17/32', attribute='0x0e 0x60 0x0002011020010db800000000000000000000000100')
   343  
   344      @staticmethod
   345      def check(env):
   346          g1 = env.g1
   347          e1 = env.e1
   348          e2 = env.e2
   349  
   350          def f():
   351              for line in e1.log().split('\n'):
   352                  if 'UPDATE message error / Attribute Flags Error / 0x600E150002011020010DB800000000000000000000000100' in line:
   353                      return True
   354              return False
   355  
   356          wait_for(f)
   357          # check e2 is still established
   358          g1.wait_for(BGP_FSM_ESTABLISHED, e2)
   359  
   360      @staticmethod
   361      def executor(env):
   362          lookup_scenario("MalformedRouteFamily").boot(env)
   363          lookup_scenario("MalformedRouteFamily").setup(env)
   364          lookup_scenario("MalformedRouteFamily").check(env)
   365  
   366  
   367  @register_scenario
   368  class MalformedAsPathSegmentLengthInvalid(object):
   369      """
   370        No.7 malformaed aspath segment length invalid
   371      """
   372  
   373      @staticmethod
   374      def boot(env):
   375          lookup_scenario("MalformedMpReachNlri").boot(env)
   376  
   377      @staticmethod
   378      def setup(env):
   379          g1 = env.g1
   380          e1 = env.e1
   381          e2 = env.e2
   382          for c in [e1, e2]:
   383              g1.wait_for(BGP_FSM_ESTABLISHED, c)
   384  
   385          # advertise malformed AS_PATH SEGMENT LENGTH
   386          # Send the attribute to the length and number of aspath is inconsistent
   387          # Attribute Type  0x02 (AS_PATH)
   388          # Attribute Flag  0x40 (well-known transitive)
   389          # Attribute Value 0x02020000ffdc (
   390          #  segment type    = 02
   391          #  segment length  = 02 -> # correct value = 01
   392          #  as number       = 65500   )
   393          e1.add_route('10.7.0.17/32', attribute='0x02 0x40 0x0202ffdc')
   394  
   395      @staticmethod
   396      def check(env):
   397          g1 = env.g1
   398          e1 = env.e1
   399          e2 = env.e2
   400  
   401          def f():
   402              for line in e1.log().split('\n'):
   403                  if 'UPDATE message error / Malformed AS_PATH / 0x4002040202FFDC' in line:
   404                      return True
   405              return False
   406  
   407          wait_for(f)
   408          # check e2 is still established
   409          g1.wait_for(BGP_FSM_ESTABLISHED, e2)
   410  
   411      @staticmethod
   412      def executor(env):
   413          lookup_scenario("MalformedAsPathSegmentLengthInvalid").boot(env)
   414          lookup_scenario("MalformedAsPathSegmentLengthInvalid").setup(env)
   415          lookup_scenario("MalformedAsPathSegmentLengthInvalid").check(env)
   416  
   417  
   418  @register_scenario
   419  class MalformedNexthopLoopbackAddr(object):
   420      """
   421        No.8 malformaed nexthop loopback addr
   422      """
   423  
   424      @staticmethod
   425      def boot(env):
   426          lookup_scenario("MalformedMpReachNlri").boot(env)
   427  
   428      @staticmethod
   429      def setup(env):
   430          g1 = env.g1
   431          e1 = env.e1
   432          e2 = env.e2
   433          for c in [e1, e2]:
   434              g1.wait_for(BGP_FSM_ESTABLISHED, c)
   435  
   436          # Malformed Invalid NEXT_HOP Attribute
   437          # Send the attribute of invalid nexthop
   438          # next-hop 127.0.0.1 -> # correct value = other than loopback and 0.0.0.0 address
   439          e1.add_route('10.7.0.17/32', nexthop='127.0.0.1')
   440  
   441      @staticmethod
   442      def check(env):
   443          g1 = env.g1
   444          e1 = env.e1
   445          e2 = env.e2
   446  
   447          def f():
   448              for line in e1.log().split('\n'):
   449                  if 'UPDATE message error / Invalid NEXT_HOP Attribute / 0x4003047F000001' in line:
   450                      return True
   451              return False
   452  
   453          wait_for(f)
   454          # check e2 is still established
   455          g1.wait_for(BGP_FSM_ESTABLISHED, e2)
   456  
   457      @staticmethod
   458      def executor(env):
   459          lookup_scenario("MalformedNexthopLoopbackAddr").boot(env)
   460          lookup_scenario("MalformedNexthopLoopbackAddr").setup(env)
   461          lookup_scenario("MalformedNexthopLoopbackAddr").check(env)
   462  
   463  
   464  @register_scenario
   465  class MalformedOriginType(object):
   466      """
   467        No.9 malformaed origin type
   468      """
   469  
   470      @staticmethod
   471      def boot(env):
   472          lookup_scenario("MalformedMpReachNlri").boot(env)
   473  
   474      @staticmethod
   475      def setup(env):
   476          g1 = env.g1
   477          e1 = env.e1
   478          e2 = env.e2
   479          for c in [e1, e2]:
   480              g1.wait_for(BGP_FSM_ESTABLISHED, c)
   481  
   482          # Invalid ORIGIN Attribute
   483          # Send the attribute of origin type 4
   484          # Attribute Type  0x01 (Origin)
   485          # Attribute Flag  0x40 (well-known transitive)
   486          # Attribute Value 0x04 (
   487          #  origin type    = 04 -> # correct value = 01 or 02 or 03 )
   488          e1.add_route('10.7.0.17/32', attribute='0x1 0x40 0x04')
   489  
   490      @staticmethod
   491      def check(env):
   492          g1 = env.g1
   493          e1 = env.e1
   494          e2 = env.e2
   495  
   496          def f():
   497              for line in e1.log().split('\n'):
   498                  if 'UPDATE message error / Invalid ORIGIN Attribute / 0x40010104' in line:
   499                      return True
   500              return False
   501  
   502          wait_for(f)
   503          # check e2 is still established
   504          g1.wait_for(BGP_FSM_ESTABLISHED, e2)
   505  
   506      @staticmethod
   507      def executor(env):
   508          lookup_scenario("MalformedOriginType").boot(env)
   509          lookup_scenario("MalformedOriginType").setup(env)
   510          lookup_scenario("MalformedOriginType").check(env)
   511  
   512  
   513  class TestGoBGPBase(unittest.TestCase):
   514  
   515      wait_per_retry = 5
   516      retry_limit = 10
   517  
   518      @classmethod
   519      def setUpClass(cls):
   520          idx = parser_option.test_index
   521          base.TEST_PREFIX = parser_option.test_prefix
   522          cls.parser_option = parser_option
   523          cls.executors = []
   524          if idx == 0:
   525              print 'unset test-index. run all test sequential'
   526              for _, v in _SCENARIOS.items():
   527                  for k, m in inspect.getmembers(v, inspect.isfunction):
   528                      if k == 'executor':
   529                          cls.executor = m
   530                  cls.executors.append(cls.executor)
   531          elif idx not in _SCENARIOS:
   532              print 'invalid test-index. # of scenarios: {0}'.format(len(_SCENARIOS))
   533              sys.exit(1)
   534          else:
   535              for k, m in inspect.getmembers(_SCENARIOS[idx], inspect.isfunction):
   536                  if k == 'executor':
   537                      cls.executor = m
   538              cls.executors.append(cls.executor)
   539  
   540      def test(self):
   541          for e in self.executors:
   542              yield e
   543  
   544  
   545  if __name__ == '__main__':
   546      output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True)
   547      if int(output) is not 0:
   548          print "docker not found"
   549          sys.exit(1)
   550  
   551      nose.main(argv=sys.argv, addplugins=[OptionParser()],
   552                defaultTest=sys.argv[0])