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