📄 proxyarplib.c
字号:
*/LOCAL void proxyArpInput ( struct arpcom * pArpcom, /* arpcom structure */ struct mbuf * pMbuf /* mbuf chain */ ) { struct ether_arp * pArp; /* ARP message */ struct in_addr srcAddr; /* source address */ struct in_addr dstAddr; /* destination address */ u_short arpOp; /* ARP operation */ pArp = mtod (pMbuf, struct ether_arp *); /* len checked in arpinput */ arpOp = ntohs(pArp->arp_op); bcopy ((caddr_t) pArp->arp_spa, (caddr_t) &srcAddr, sizeof (srcAddr)); bcopy ((caddr_t) pArp->arp_tpa, (caddr_t) &dstAddr, sizeof (dstAddr)); if (arpDebug) /* ARP debugging info */ { logMsg ("op:%s (if 0x%x) src: 0x%x [%s] dst: 0x%x ", (arpOp == ARPOP_REQUEST) ? (int) "request" : (int) "reply", ntohl (pArpcom->ac_ipaddr.s_addr), ntohl (srcAddr.s_addr), (int) ether_sprintf (pArp->arp_sha), ntohl (dstAddr.s_addr), 0); if (arpOp != ARPOP_REQUEST) logMsg ("[%s]", (int) ether_sprintf (pArp->arp_tha), 0, 0, 0, 0 ,0); logMsg ("\n", 0, 0, 0, 0, 0, 0); } /* sanity checks */ if ((bcmp ((caddr_t) pArp->arp_sha, (caddr_t) etherbroadcastaddr, sizeof (pArp->arp_sha)) == 0) || in_broadcast (srcAddr, (struct ifnet *)pArpcom)) return; semTake (proxySemId, WAIT_FOREVER); switch (arpOp) { case ARPOP_REQUEST: if (proxyIsAproxyNet (&pArpcom->ac_ipaddr)) { /* * Received an ARP request from a proxy network. Add * client if it is not registered (and arpRegister is enabled). * Update client entry in the ARP cache. */ if (arpRegister && !proxyIsAClient (&srcAddr)) (void) proxyClientAdd (pArpcom, &srcAddr); (void) arpCmd (SIOCSARP, &srcAddr, pArp->arp_sha, NULL); } if ((proxyIsAproxyNet (&dstAddr) || proxyIsAMainNet (&dstAddr)) && (dstAddr.s_addr != pArpcom->ac_ipaddr.s_addr)) { /* * An ARP request for either a proxy or main interface on * which the source doesn't reside. Answer it. Otherwise * the interfaces will be hidden. */ proxyArpReply (pArpcom, pMbuf, ntohs (pArp->arp_pro)); if (proxySendTrailer (pArpcom, pArp)) proxyArpReply (pArpcom, pMbuf, ETHERTYPE_TRAIL); semGive (proxySemId); return; } if (proxyIsAClient (&dstAddr)) /* dest is a proxy client */ { /* * The destination is a proxy client. If the client does not * reside on the interface from where the request was generated, * then reply (otherwise the client should answer for itself). * Send a trailer response if trailers are enabled on interface. */ if (!proxyIsAClientOnNet (&pArpcom->ac_ipaddr, &dstAddr)) { proxyArpReply (pArpcom, pMbuf, ntohs (pArp->arp_pro)); if (proxySendTrailer (pArpcom, pArp)) proxyArpReply (pArpcom, pMbuf, ETHERTYPE_TRAIL); } } else /* dest not a proxy client */ { if (proxyIsAClient (&srcAddr)) { /* * The ARP request came from a proxy client so we must try * to resolve it. First look into the ARP cache. If we * know about the destination, send a reply. Otherwise, try * to resolve the address by forwarding the ARP request onto * the client's main network. (Note: we only have to * forward it to the main network because all other proxy * client's we should know about). */ if (arpCmd (SIOCGARP, &dstAddr, (u_char *) NULL, (int *) NULL) == OK) { /* * It is ok if the entry times out after we * reply to the client because we will just reARP for * the host anyway. */ proxyArpReply (pArpcom, pMbuf, ntohs (pArp->arp_pro)); if (proxySendTrailer (pArpcom, pArp)) proxyArpReply (pArpcom, pMbuf, ETHERTYPE_TRAIL); } else proxyArpRequestFwd (&srcAddr, pMbuf); } } break; case ARPOP_REPLY: /* * Received an ARP reply. If it is for a proxy client and we * previously sent it out to be resolved (hwaddr is for us) then * forward it on to the client. */ if ((proxyIsAClient (&dstAddr)) && (!proxyIsAClientOnNet (&pArpcom->ac_ipaddr, &dstAddr)) && (bcmp ((caddr_t) pArp->arp_tha, (caddr_t) pArpcom->ac_enaddr, sizeof (pArpcom->ac_enaddr)) == 0)) { proxyArpReplyFwd (&dstAddr, pMbuf); if ((arpCmd (SIOCGARP, &srcAddr, (u_char *) NULL, (int *) NULL) == ERROR) && (errno == ENXIO)) { /* * if the source of the reply in not in the ARP cache, * then send a trailer response if we want to negotiate * trailers on the input interface. Only do this when * adding the host for the first time. */ if ((pArpcom->ac_if.if_flags & IFF_NOTRAILERS) == 0) proxyArpReply (pArpcom, pMbuf, ETHERTYPE_TRAIL); } (void) arpCmd (SIOCSARP, &srcAddr, pArp->arp_sha, (int *) NULL); } break; default: break; } semGive (proxySemId); }/********************************************************************************* proxyArpReply - generate an ARP reply** This routine responds to an ARP request message. It converts the request* into a reply and ships it out on the same interface from which it* arrived. The proxyArpReply() routine gets called when an ARP request* comes in for a proxy client (from a host on a different interface), or* when a proxy client generates an ARP request for an non proxy host (that* we know about).** <pArpcom> is the `arpcom' structure of the interface where the ARP message* arrived. <pMbuf> is the mbuf chain of the original ARP message. <proto>* specifies the format of the ARP reply protocol type (it is either* ETHERTYPE_IP or ETHERTYPE_TRAILERS).** RETURNS: N/A*/LOCAL void proxyArpReply ( FAST struct arpcom * pArpcom, /* arpcom structure */ FAST struct mbuf * pMbuf, /* mbuf chain */ int proto /* format of protocol */ ) { struct ether_arp * pArp; /* ARP message */ struct in_addr srcAddr; /* source address */ pArp = mtod (pMbuf, struct ether_arp *); /* * Add the source to ARP cache because chances are the destination will * (shortly) be ARPing for source. If the source is already in the ARP * cache, this updates the ARP timers and prevents the ARP entries from * timing out. */ bcopy ((caddr_t) pArp->arp_spa, (caddr_t) &srcAddr, sizeof (srcAddr)); (void) arpCmd (SIOCSARP, &srcAddr, (u_char *)pArp->arp_sha, (int *) NULL); /* switch source and target addresses */ proxyArpSend ((struct ifnet *) pArpcom, ARPOP_REPLY, proto, pArp->arp_tpa, pArp->arp_sha, pArp->arp_spa); }/********************************************************************************* proxyArpRequestFwd - forward an ARP request** This routine forwards an ARP request message, pointed to by* <pMbuf>, from a proxy client, specified by <pClientAddr>, onto the* client's main network. It gets called when a proxy client ARPs for an* unknown non proxy client. Caller must have taken `proxySemId' before this* routine is called.** RETURNS: N/A*/LOCAL void proxyArpRequestFwd ( struct in_addr * pClientAddr, /* proxy client addr */ struct mbuf * pMbuf /* mbuf chain */ ) { PROXY_CLNT * pClient; /* proxy client */ struct ether_arp * pArp; /* ARP message */ struct sockaddr_in sin; /* interface sin */ struct ifaddr * pIfa; /* interface address */ /* find the client's main network interface */ if ((pClient = proxyClientFind (pClientAddr)) == NULL) return; SIN_FILL (&sin, AF_INET, pClient->pNet->mainAddr.s_addr, 0); if ((pIfa = ifa_ifwithaddr ((struct sockaddr *) &sin)) == NULL) return; if (proxyArpVerbose) /* print debugging info */ logMsg ("(forward to if 0x%x) ", ntohl (pClient->pNet->mainAddr.s_addr), 0, 0, 0, 0, 0); /* * Leave the client as the source protocol address so when the reply * comes back we know where to forward the reply. */ pArp = mtod (pMbuf, struct ether_arp *); proxyArpSend (pIfa->ifa_ifp, ntohs (pArp->arp_op), ntohs (pArp->arp_pro), pArp->arp_spa, pArp->arp_tha, pArp->arp_tpa); }/********************************************************************************* proxyArpReplyFwd - forward an ARP reply** This routine forwards an ARP reply, pointed to by <pMbuf>, to the proxy* client specified by <pClientAddr>. The ARP reply resolves an ARP request* previously forwarded by proxyArpRequestFwd(). Trailers responses are not* forwarded onto non trailer interfaces. Caller must have taken `proxySemId'* before this routine is called.** INTERNAL* The ARP cache timeout in the proxy server, for the proxy client, must be* greater than the ARP retry time on the client. That is, the client must* stay in the proxy server ARP cache for at least as long as it takes the* client to timeout and retransmit the ARP request. Otherwise, the server* could falsely throw away an ARP reply and cause the client to send another* ARP request. This, however, is not critical and doesn't seem to be a* problem since the ARP cache timeout on a completed entry is 20 minutes.** RETURNS: N/A*/LOCAL void proxyArpReplyFwd ( struct in_addr * pClientAddr, /* proxy client addr */ struct mbuf * pMbuf /* mbuf chain */ ) { PROXY_CLNT * pClient; /* proxy client */ struct sockaddr_in sin; /* interface sin */ struct ifaddr * pIfa; /* interface address */ struct ether_arp * pArp; /* ARP message */ u_short arpProto; /* ARP type */ u_char hwAddr [6]; /* client hw address */ /* find the client's the proxy interface */ if ((pClient = proxyClientFind (pClientAddr)) == NULL) return; SIN_FILL (&sin, AF_INET, pClient->pNet->proxyAddr.s_addr, 0); if ((pIfa = ifa_ifwithaddr ((struct sockaddr *) &sin)) == NULL) return; if (proxyArpVerbose) /* print debugging info */ logMsg ("(forward to if 0x%x)", ntohl (pClient->pNet->mainAddr.s_addr), 0, 0, 0, 0, 0); pArp = mtod (pMbuf, struct ether_arp *); /* * Don't forward trailer packets onto non-trailer interfaces. We probably * could eat this packet entirely since trailer responses are additional * but who really knows what other machines are doing, so to be cautious * and pass it through as a normal IP proto type. */ if ((ntohs (pArp->arp_pro) == ETHERTYPE_TRAIL) && (((struct arpcom *)(pIfa->ifa_ifp))->ac_if.if_flags & IFF_NOTRAILERS)) arpProto = ETHERTYPE_IP; else arpProto = ntohs (pArp->arp_pro); /* the clients hardware address is the target hardware address */ if (arpCmd (SIOCGARP, pClientAddr, hwAddr, (int *) NULL) == OK) proxyArpSend (pIfa->ifa_ifp, ntohs (pArp->arp_op), arpProto, pArp->arp_spa, hwAddr, pArp->arp_tpa); }/********************************************************************************* proxyArpSend - generate and send an ARP message** This routine constructs and sends an ARP message over the network interface* specified by <pIf>. <op> specifies the ARP operation, <proto> is the format* of protocol address. <srcProtoAddr> is the source protocol address,* <dstHwAddr> is the destination hardware address and <dstProtoAddr> is the* destination protocol addresses.** RETURNS: N/A*/LOCAL void proxyArpSend ( struct ifnet * pIf, /* interface pointer */ int op, /* ARP op */ int proto, /* ARP protocol */ u_char * srcProtoAddr, /* src ip address */ u_char * dstHwAddr, /* dest hw address */ u_char * dstProtoAddr /* dest ip address */ ) { FAST struct mbuf * pMbuf; /* mbuf chain */ FAST struct ether_arp * pArp; /* ARP message */ struct ether_header * pEh; /* ether header */ struct sockaddr sa; /* sockaddr structure */ if ((pMbuf = mHdrClGet(M_DONTWAIT, MT_DATA, sizeof(*pArp), TRUE)) == NULL) return; pMbuf->m_len = sizeof(*pArp); pMbuf->m_pkthdr.len = sizeof(*pArp); MH_ALIGN(pMbuf, sizeof(*pArp)); pArp = mtod(pMbuf, struct ether_arp *); /* fill in ARP message */ bzero ((caddr_t) pArp, sizeof (struct ether_arp)); pArp->arp_hrd = htons (ARPHRD_ETHER); pArp->arp_pro = htons (proto); pArp->arp_hln = sizeof (pArp->arp_sha); pArp->arp_pln = sizeof (pArp->arp_spa); pArp->arp_op = htons (op); bcopy ((caddr_t) ((struct arpcom *) pIf)->ac_enaddr, (caddr_t) pArp->arp_sha, sizeof (pArp->arp_sha)); bcopy ((caddr_t) srcProtoAddr, (caddr_t) pArp->arp_spa, sizeof (pArp->arp_spa)); bcopy ((caddr_t) dstProtoAddr, (caddr_t) pArp->arp_tpa, sizeof (pArp->arp_tpa)); bzero ((caddr_t) &sa, sizeof (sa)); sa.sa_family = AF_UNSPEC; pEh = (struct ether_header *) sa.sa_data; pEh->ether_type = ETHERTYPE_ARP; /* switched in ether_output */ if (op == ARPOP_REQUEST) { bcopy ((caddr_t) etherbroadcastaddr, (caddr_t) pEh->ether_dhost, sizeof (pEh->ether_dhost)); } else { bcopy ((caddr_t) dstHwAddr, (caddr_t) pArp->arp_tha, sizeof (pArp->arp_tha)); bcopy ((caddr_t) dstHwAddr, (caddr_t) pEh->ether_dhost, sizeof (pEh->ether_dhost)); } if (proxyArpVerbose) { logMsg ("%s (%x): src: 0x%x [%s] dst : 0x%x ", (op == ARPOP_REQUEST) ? (int) "request" : (int) "reply", proto, *((int *) pArp->arp_spa), (int) ether_sprintf (pArp->arp_sha), *((int *) pArp->arp_tpa), 0); if (op != ARPOP_REQUEST) logMsg ("[%s]", (int) ether_sprintf (pArp->arp_tha), 0, 0, 0, 0, 0); logMsg ("\n", 0, 0, 0, 0, 0, 0); } (*pIf->if_output) (pIf, pMbuf, &sa, (struct rtentry *) NULL); }/********************************************************************************* proxyNetCreate - create a proxy ARP network** This routine creates a proxy network with the interface <proxyAddr> as the* proxy network and the interface <mainAddr> as the main network. The* interfaces and the routing tables must be set up correctly, prior to* calling this routine. That is, the interfaces must be attached, addresses* must be set, and there should be a network route to <mainAddr> and no* routes to <proxyAddr>.** <proxyAddr> and <mainAddr> must reside in the same network address space.** RETURNS: OK, or ERROR if unsuccessful.** ERRNO:* S_proxyArpLib_INVALID_INTERFACE* S_proxyArpLib_INVALID_ADDRESS** INTERNAL* The `proxyArpParanoia' flag does extra checking to make sure the* user is using proxy ARP the way we intended (i.e., over the backplane).* Otherwise, unless the person is careful, serious network problems can* occur.**/STATUS proxyNetCreate (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -