📄 proxy.c
字号:
if (server->radport == 0) { server->radport = radius_port; } if (server->acctport == 0) { server->acctport = radacct_port; } if ((ipaddr == ouraddress) && ((server->radport == radius_port) || (server->acctport == radacct_port))) { ipaddr = 0; /* handle ourselves, do not forward */ } server->ipaddr = ipaddr; memcpy(server->secret, secret, strlen(secret)); memcpy(server->realm, realm, strlen(realm)); if (strcmp(realm, "DEFAULT") == 0) { server_default = server; } else if (strcmp(realm, "NOREALM") == 0) { server_norealm = server; } if (servers == (PEER *)NULL) { /* first one */ servers = server; curserv = server; } else { curserv->next = server; curserv = server; } nproxy++; } fclose(fd); last_update_time = statbuf.st_mtime; debug("found %d proxy realms\n", nproxy); return(0);}/************************************************************************* ************************************************************************* Subroutines related to forwarding a Proxy request from a client to the appropriate server handle_proxy(authreq) push_proxy(authreq) find_server(number, realm) find_server_byaddr(ipaddr, port) send_proxy2server(authreq, server) getnextid(authreq) ************************************************************************* *************************************************************************//************************************************************************* * * Function: handle_proxy * * Purpose: Called by rad_request() to check if access-request should * be forwarded to another server. * Called by rad_acctreq() to forward acct-request if needed. * * Returns: * -1 on error * 0 if this request was not forwarded * 1 if this request was forwarded * Side-Effects: * Sets REQ_PROXY flag in authreq if request was forwarded * * *************************************************************************/int handle_proxy(AUTH_REQ*authreq){ PEER *server; VALUE_PAIR *namepair; VALUE_PAIR *pair; char *name; char namebuf[256]; char *number; char *ptr; char *realm; int ret; realm = (char *)NULL; number = (char *)NULL; namebuf[0] = '\0'; name = namebuf; if (authreq == (AUTH_REQ *)NULL) { return -1; } if (authreq->code != PW_AUTHENTICATION_REQUEST && authreq->code != PW_ACCOUNTING_REQUEST) { /* should not happen unless client sent bogus message */ debug("handle_proxy called for packet type %d unexpectedly\n", authreq->code); authreq->flags |= REQ_ERR|REQ_FREE; return -1; } namepair = get_attribute(authreq->request, PW_USER_NAME); if (namepair != (VALUE_PAIR *)NULL) { memcpy(namebuf, namepair->strvalue, namepair->lvalue); namebuf[namepair->lvalue] = '\0'; if ((realm=strchr((const char *)name, '@')) != (char *)NULL) { *realm = '\0'; realm++; } else if ((ptr=strchr((const char *)name, '/')) != (char *)NULL) { *ptr = '\0'; ptr++; realm = name; name = ptr; } else { realm = (char *)NULL; } } pair = get_attribute(authreq->request, PW_CALLED); if (pair != (VALUE_PAIR *)NULL) { number = pair->strvalue; } /* look up number or realm in the list of servers. If a proxy * is found, parse the packet, unencrypt the password if * any, re-encrypt the password (if any), attach a * proxy-state with push_proxy(), and forward it to the proxy. * Use the same Request Authenticator (in case of CHAP) but * use a new Id */ if ((server = find_server(number, realm)) == (PEER *)NULL) { if (namepair != (VALUE_PAIR *)NULL) { strncpy(authreq->name, namepair->strvalue, 64); authreq->name[63] = '\0'; } else { authreq->name[0] = '\0'; } return 0; /* no proxy */ } strncpy(authreq->realm, server->realm, 64); strncpy(authreq->name, name, 64); authreq->name[63] = '\0'; if (server->ipaddr == 0) { /* this is the server for this realm */ return 0; } authreq->flags |= REQ_PROXY; if (server->flags & PEER_IPASS) { if (authreq->code == PW_AUTHENTICATION_REQUEST) { ret = rad_forw_ipass(authreq, sockfd, authreq->packet); authreq->flags |= REQ_FREE; return ret; } else if (authreq->code == PW_ACCOUNTING_REQUEST) { ret = rad_forw_ipass(authreq, acctfd, authreq->packet); authreq->flags |= REQ_FREE; return 0; } else { authreq->flags |= REQ_ERR|REQ_FREE; return -1; } } if (authreq->code == PW_AUTHENTICATION_REQUEST) { if (decrypt_password(authreq, authreq->secret) != (char *)NULL) { encrypt_password(authreq, server->secret); } } /* If remote server cannot handle proxy, delete realm from User-Name */ if ( server->flags & PEER_NOPROXY ) { if (namepair != (VALUE_PAIR *)NULL) { strcpy(namepair->strvalue,name); namepair->lvalue = strlen(name); } } else { push_proxy(authreq); } send_proxy2server(authreq, server); return 1;}/************************************************************************* * * Function: push_proxy * * Purpose: Adds a Proxy-State to the end of a packet * Note that RADIUS requires that Proxy-State always be * added after any existing Proxy-State attributes. * * Any changes made here must also be made in pop_proxy() * *************************************************************************/voidpush_proxy(AUTH_REQ*authreq){ DICT_ATTR *attr; VALUE_PAIR *pair; VALUE_PAIR *list; UINT4 tmp; u_short tmps; pair = pairalloc("push_proxy"); /* Proxy-State contains: Timestamp, Client, Port, Id in network order, a pad byte, and 16 octets of Request Authenticator */ if((attr = dict_attrget(PW_PROXY)) == (DICT_ATTR *)NULL) { debug("add Proxy (%d) to dictionary\n", PW_PROXY); strcpy(pair->name, "Proxy"); pair->type = PW_TYPE_STRING; } else { strcpy(pair->name, attr->name); pair->type = attr->type; } pair->attribute = PW_PROXY; pair->lvalue = 28; /* length of data */ tmp = htonl(authreq->timestamp); memcpy(pair->strvalue, (char *)&tmp, 4); tmp = htonl(authreq->ipaddr); memcpy(pair->strvalue+4, (char *)&tmp, 4); tmps = htons(authreq->udp_port); memcpy(pair->strvalue+8, (char *)&tmps, 2); memcpy(pair->strvalue+10, (char *)&(authreq->id), 1); memset(pair->strvalue+11, 0, 1); /* zero pad */ memcpy(pair->strvalue+12, authreq->vector, AUTH_VECTOR_LEN); if ((list = authreq->request) == (VALUE_PAIR *)NULL) { authreq->request = pair; } else { while(list->next != (VALUE_PAIR *)NULL) { list = list->next; } list->next = pair; }}/************************************************************************* * * Function: find_server * * Purpose: Returns server to forward to based on number or realm * Number takes precedence * *************************************************************************/PEER * find_server(char *number,char *realm){ extern PEER *servers; extern PEER *server_default; extern PEER *server_norealm; PEER *server; PEER *maybe; maybe = (PEER *)NULL; server=servers; /* In a future version we may want to match with or without area code */ while(server != (PEER *)NULL) { if ((number != (char *)NULL) && (strcmp(server->realm, number) == 0)) { return server; } if ((realm != (char *)NULL) && (strcmp(server->realm, realm) == 0)) { maybe = server; } server = server->next; } if (maybe == (PEER *)NULL) { if (realm != (char *)NULL) { maybe = server_default; } else { maybe = server_norealm; } } return maybe;}/************************************************************************* * * Function: find_server_byaddr * * Purpose: Returns proxy server based on IP address and source port * *************************************************************************/PEER *find_server_byaddr(UINT4 ipaddr,u_short port){ PEER *server; extern PEER *servers; server=servers; while ((server != (PEER *)NULL) && !((server->ipaddr == ipaddr) && ((server->acctport == port) || (server->radport == port))) ) { server = server->next; } return server;}/************************************************************************* * * Function: send_proxy2server * * Purpose: Forward a proxy request to a server * Calling routine has already encrypted password (if any) * and added our Proxy-State * *************************************************************************/void send_proxy2server(AUTH_REQ*authreq,PEER*server){ extern AUTH_REQ *first_forwarded; AUTH_HDR *auth; char ip_str[32]; int fd; u_char saveid; u_short total_length; req2str(ip_str, sizeof(ip_str), authreq); auth = (AUTH_HDR *)send_buffer; if (authreq->code == PW_AUTHENTICATION_REQUEST) { authreq->forw_port = server->radport; fd = proxyfd; } else if (authreq->code == PW_ACCOUNTING_REQUEST) { authreq->forw_port = server->acctport; fd = proxyacctfd; } else { log_err("unknown request type %d from %s ignored\n", authreq->code, ip_str); authreq->flags |= REQ_ERR|REQ_FREE; return; } authreq->forw_id = getnextid(authreq); /* getnextid sets REQ_ERR flag if unable to allocate id */ if ((authreq->flags & REQ_ERR) == REQ_ERR) { return; } saveid = authreq->id; authreq->id = authreq->forw_id; authreq->forw_addr = server->ipaddr; memcpy(authreq->forw_vector, authreq->vector, AUTH_VECTOR_LEN); strcpy(authreq->forw_secret, server->secret); debug("forwarding request from %s to %s/%d.%d for %s\n", ip_str, ipaddr2strp(authreq->forw_addr), authreq->forw_port, authreq->forw_id, authreq->realm); total_length = build_packet(authreq, authreq->request, (char *)NULL, authreq->code, FW_SERVER, send_buffer, sizeof(send_buffer)); authreq->id = saveid; memcpy(authreq->forw_vector, auth->vector, AUTH_VECTOR_LEN); /* forward it to the server */ send_packet(fd, authreq->forw_addr, authreq->forw_port, send_buffer, total_length); if (!(authreq->flags & REQ_DUP)) { authreq->next = first_forwarded; first_forwarded = authreq; if (authreq == authreq->next) { log_err("ERROR: circular queue detected at %d\n", __LINE__); } } return;}/************************************************************************* * * Function: getnextid * * Purpose: Returns next ID for use in forwarding to this server * Use one ID counter 0..255 for all forwarded packets * *************************************************************************/u_char getnextid(AUTH_REQ *authreq){ extern AUTH_REQ *first_forwarded; AUTH_REQ *qp; AUTH_REQ *prevqp; static char inuse[256]; u_short newid; static u_char curid = 0; static int flushcount = 0; extern int max_proxy_time; extern UINT4 now; memset(inuse, 0, 256); prevqp = (AUTH_REQ *)NULL; qp = first_forwarded; while (qp != (AUTH_REQ *)NULL) { if (qp->timestamp + max_proxy_time < now) { if (++flushcount % 100 == 0) { debug("%d proxy requests expired unanswered\n",flushcount); } if (prevqp == (AUTH_REQ *)NULL) { first_forwarded = qp->next; reqfree(qp,"getnextid"); qp = first_forwarded; } else { prevqp->next = qp->next; reqfree(qp,"getnextid"); qp = prevqp->next; } } else { if (authreq->ipaddr == qp->ipaddr && authreq->udp_port == qp->udp_port && authreq->id == qp->id) { authreq->flags |= REQ_DUP|REQ_FREE; return qp->forw_id; } inuse[qp->forw_id]++; if (qp == qp->next) { log_err("ERROR: circular queue detected at %d\n", __LINE__); qp->next = (AUTH_REQ *)NULL; } prevqp = qp; qp = qp->next; } } for (newid = curid; newid <= 255; newid++) { if (inuse[newid] == 0) { curid = ((newid+1) & 0xff); return newid; } } for (newid = 0; newid < curid; newid++) { if (inuse[newid] == 0) { curid = ((newid+1) & 0xff); return newid; } } /* no ids left, so log an error and mark packet for discard */ log_err("getnextid: out of IDs, dropping packet from %s\n", req2strp(authreq)); authreq->flags |= REQ_ERR|REQ_FREE; return 0;}/************************************************************************* ************************************************************************* Misc subroutines for proxy ************************************************************************* *************************************************************************//************************************************************************* * * Function: proxy_report * * Purpose: Log proxy queue status for debugging purposes * * Uses External: first_forwarded * *************************************************************************/void proxy_report(void){ AUTH_REQ *qp; UINT4 oldest; UINT4 clock; int n; if (first_forwarded != (AUTH_REQ *)NULL) { qp = first_forwarded; n = 0; clock = (UINT4)time((time_t *)NULL); oldest = clock; while (qp != (AUTH_REQ *)NULL) { n++; if (qp->timestamp < oldest) { oldest = qp->timestamp; } qp = qp->next; } clock = clock - oldest; log_err("%d in proxy queue, oldest %d seconds ago\n", n, clock); } else { log_err("no entries in proxy queue\n"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -