aboutsummaryrefslogtreecommitdiffstats
path: root/net/zebra/files/patch-ripd
blob: 4178aaac23c6e183d1bd1a7054cabc28e43dc6c4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
--- lib/if.c.orig   Fri Jun 21 23:49:50 2002
+++ lib/if.c    Mon Oct 14 17:25:42 2002
@@ -553,6 +553,65 @@
   return NULL;
 }
 
+/* Find the IPv4 address on our side that will be used when packets
+   are sent to dst. */
+struct connected *
+connected_lookup_address (struct interface *ifp, struct in_addr dst)
+{
+  struct prefix addr;
+  struct prefix best;
+  listnode cnode;
+  struct prefix *p;
+  struct connected *c;
+  struct connected *match;
+
+  /* Zero structures - get rid of rubbish from stack */
+  memset(&addr, 0, sizeof(addr));
+  memset(&best, 0, sizeof(best));
+
+  addr.family = AF_INET;
+  addr.u.prefix4 = dst;
+  addr.prefixlen = IPV4_MAX_BITLEN;
+
+  match = NULL;
+
+  for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+    {
+      c = getdata (cnode);
+
+      if (if_is_pointopoint (ifp))
+   {
+     p = c->address;
+
+     if (p && p->family == AF_INET)
+       {
+#ifdef OLD_RIB  /* PTP  links are conventionally identified 
+           by the address of the far end - MAG */
+         if (IPV4_ADDR_SAME (&p->u.prefix4, &dst))
+       return c;
+#endif
+         p = c->destination;
+         if (p && IPV4_ADDR_SAME (&p->u.prefix4, &dst))
+       return c;
+       }
+   }
+      else
+   {
+     p = c->address;
+
+     if (p->family == AF_INET)
+       {
+         if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen)
+       {
+         best = *p;
+         match = c;
+       }
+       }
+   }
+    }
+  return match;
+}
+
 /* Check the connected information is PtP style or not.  */
 int
 ifc_pointopoint (struct connected *ifc)
--- ./lib/if.h.orig Fri Jun 21 23:49:50 2002
+++ ./lib/if.h  Mon Oct 14 17:25:42 2002
@@ -202,6 +202,7 @@
 void connected_free (struct connected *);
 void connected_add (struct interface *, struct connected *);
 struct connected  *connected_delete_by_prefix (struct interface *, struct prefix *);
+struct connected  *connected_lookup_address (struct interface *, struct in_addr);
 int ifc_pointopoint (struct connected *);
 
 #ifndef HAVE_IF_NAMETOINDEX
--- ./ripd/ripd.c.orig  Mon Jul  1 02:57:22 2002
+++ ./ripd/ripd.c   Tue Oct 15 10:02:11 2002
@@ -55,8 +55,8 @@
 /* Prototypes. */
 void rip_event (enum rip_event, int);
 
-void rip_output_process (struct interface *, struct sockaddr_in *, 
-            int, u_char);
+void rip_output_process (struct interface *, struct prefix *,
+            struct sockaddr_in *, int, u_char);
 
 /* RIP output routes type. */
 enum
@@ -955,7 +955,14 @@
 {
   caddr_t lim;
   struct rte *rte;
+  struct prefix_ipv4 ifaddr;
+  struct prefix_ipv4 ifaddrclass;
+  struct connected *c;
+  int subnetted;
       
+  /* We don't know yet. */
+  subnetted = -1;
+
   /* The Response must be ignored if it is not from the RIP
      port. (RFC2453 - Sec. 3.9.2)*/
   if (ntohs (from->sin_port) != RIP_PORT_DEFAULT) 
@@ -1108,23 +1115,51 @@
    {
      u_int32_t destination;
 
-     destination = ntohl (rte->prefix.s_addr);
-
-     if (destination & 0xff) 
+     if (subnetted == -1)
        {
-         masklen2ip (32, &rte->mask);
+         c = connected_lookup_address (ifp, from->sin_addr);
+         if (c != NULL)
+       {
+         memcpy (&ifaddr, c->address, sizeof (struct prefix_ipv4));
+         memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
+         apply_classful_mask_ipv4 (&ifaddrclass);
+         subnetted = 0;
+         if (ifaddr.prefixlen > ifaddrclass.prefixlen)
+           subnetted = 1;
+       }
        }
-     else if ((destination & 0xff00) || IN_CLASSC (destination)) 
-       {
+
+     destination = ntohl (rte->prefix.s_addr);
+
+     if (IN_CLASSA (destination))
+         masklen2ip (8, &rte->mask);
+     else if (IN_CLASSB (destination))
+         masklen2ip (16, &rte->mask);
+     else if (IN_CLASSC (destination))
          masklen2ip (24, &rte->mask);
+
+     if (subnetted == 1)
+       masklen2ip (ifaddrclass.prefixlen,
+           (struct in_addr *) &destination);
+     if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
+         ifaddrclass.prefix.s_addr))
+       {
+         masklen2ip (ifaddr.prefixlen, &rte->mask);
+         if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
+       masklen2ip (32, &rte->mask);
+         if (IS_RIP_DEBUG_EVENT)
+       zlog_info ("Subnetted route %s", inet_ntoa (rte->prefix));
        }
-     else if ((destination & 0xff0000) || IN_CLASSB (destination)) 
+     else
        {
-         masklen2ip (16, &rte->mask);
+         if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
+       continue;
        }
-     else 
+
+     if (IS_RIP_DEBUG_EVENT)
        {
-         masklen2ip (8, &rte->mask);
+         zlog_info ("Resultant route %s", inet_ntoa (rte->prefix));
+         zlog_info ("Resultant mask %s", inet_ntoa (rte->mask));
        }
    }
 
@@ -1353,7 +1388,7 @@
       ntohl (rte->metric) == RIP_METRIC_INFINITY)
     {  
       /* All route with split horizon */
-      rip_output_process (ifp, from, rip_all_route, packet->version);
+      rip_output_process (ifp, NULL, from, rip_all_route, packet->version);
     }
   else
     {
@@ -1884,8 +1919,8 @@
 
 /* Send update to the ifp or spcified neighbor. */
 void
-rip_output_process (struct interface *ifp, struct sockaddr_in *to,
-           int route_type, u_char version)
+rip_output_process (struct interface *ifp, struct prefix *ifaddr,
+           struct sockaddr_in *to, int route_type, u_char version)
 {
   int ret;
   struct stream *s;
@@ -1894,8 +1929,11 @@
   struct rip_interface *ri;
   struct prefix_ipv4 *p;
   struct prefix_ipv4 classfull;
+  struct prefix_ipv4 ifaddrclass;
+  struct connected *c;
   int num;
   int rtemax;
+  int subnetted;
 
   /* Logging output event. */
   if (IS_RIP_DEBUG_EVENT)
@@ -1946,29 +1984,60 @@
          rtemax -=1;
     }
 
+  if (version == RIPv1)
+    {
+      if (ifaddr == NULL)
+   {
+     c = connected_lookup_address (ifp, to->sin_addr);
+     if (c != NULL)
+       ifaddr = c->address;
+   }
+      if (ifaddr == NULL)
+   {
+     zlog_warn ("cannot find source address for packets to neighbor %s",
+            inet_ntoa (to->sin_addr));
+     return;
+   }
+      memcpy (&ifaddrclass, ifaddr, sizeof (struct prefix_ipv4));
+      apply_classful_mask_ipv4 (&ifaddrclass);
+      subnetted = 0;
+      if (ifaddr->prefixlen > ifaddrclass.prefixlen)
+   subnetted = 1;
+    }
+
   for (rp = route_top (rip->table); rp; rp = route_next (rp))
     if ((rinfo = rp->info) != NULL)
       {
-   /* Some inheritance stuff:                                          */
-   /* Before we process with ipv4 prefix we should mask it             */
-   /* with Classful mask if we send RIPv1 packet.That's because        */
-   /* user could set non-classful mask or we could get it by RIPv2     */
-   /* or other protocol. checked with Cisco's way of life :)           */
+   /* For RIPv1, if we are subnetted, output subnets in our network    */
+   /* that have the same mask as the output "interface". For other     */
+   /* networks, only the classfull version is output.                  */
    
    if (version == RIPv1)
      {
-       memcpy (&classfull, &rp->p, sizeof (struct prefix_ipv4));
+       p = (struct prefix_ipv4 *) &rp->p;
 
        if (IS_RIP_DEBUG_PACKET)
-         zlog_info("%s/%d before RIPv1 mask check ",
-           inet_ntoa (classfull.prefix), classfull.prefixlen);
-
-       apply_classful_mask_ipv4 (&classfull);
-       p = &classfull;
+         zlog_info("RIPv1 mask check, %s/%d considered for output",
+           inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
 
+       if (subnetted &&
+       prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
+         {
+       if ((ifaddr->prefixlen != rp->p.prefixlen) &&
+           (rp->p.prefixlen != 32))
+         continue;
+         }
+       else
+         {
+       memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
+       apply_classful_mask_ipv4(&classfull);
+       if (rp->p.u.prefix4.s_addr != 0 &&
+           classfull.prefixlen != rp->p.prefixlen)
+         continue;
+         }
        if (IS_RIP_DEBUG_PACKET)
-         zlog_info("%s/%d after RIPv1 mask check",
-           inet_ntoa (p->prefix), p->prefixlen);
+         zlog_info("RIPv1 mask check, %s/%d made it through",
+           inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
      }
    else 
      p = (struct prefix_ipv4 *) &rp->p;
@@ -2109,7 +2178,7 @@
       if (IS_RIP_DEBUG_EVENT)
    zlog_info ("multicast announce on %s ", ifp->name);
 
-      rip_output_process (ifp, NULL, route_type, version);
+      rip_output_process (ifp, NULL, NULL, route_type, version);
       return;
     }
 
@@ -2136,7 +2205,8 @@
               if_is_pointopoint (ifp) ? "unicast" : "broadcast",
               inet_ntoa (to.sin_addr), ifp->name);
 
-         rip_output_process (ifp, &to, route_type, version);
+         rip_output_process (ifp, connected->address, &to, route_type,
+                 version);
        }
    }
     }
@@ -2224,7 +2294,7 @@
    to.sin_port = htons (RIP_PORT_DEFAULT);
 
    /* RIP version is rip's configuration. */
-   rip_output_process (ifp, &to, route_type, rip->version);
+   rip_output_process (ifp, NULL, &to, route_type, rip->version);
       }
 }