Date: Fri, 21 Jun 2002 03:12:33 +0300 From: Giorgos Keramidas <keramida@FreeBSD.org> To: hackers@FreeBSD.org Subject: Re: Limiting clients per source IP address (ftpd, inetd, etc.) Message-ID: <20020621001233.GB2178@hades.hell.gr> In-Reply-To: <20020621000924.GA2178@hades.hell.gr> References: <20020621000924.GA2178@hades.hell.gr>
next in thread | previous in thread | raw e-mail | index | archive | help
--5I6of5zJg18YgZEa Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On 2002-06-21 03:09 +0000, Giorgos Keramidas wrote: > Below is a prototype I'm playing the last few days with, trying to > make something that implements the above scheme using <queue.h> > macros. Now, what do you all think about this? Does it sound like a > nice idea to pursue further? It would be nice if I also included the source *grin* %%% #include <netinet/in.h> #include <sys/queue.h> #include <sys/types.h> #include <assert.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> LIST_HEAD(cpidhead, childpid); struct childpid { pid_t cp_pid; /* Process ID of a child. */ LIST_ENTRY(childpid) cp_entry; /* Glue to the other list elements. */ }; LIST_HEAD(ciphead, childaddr); struct childaddr { struct in_addr ca_addr; /* Address of a host. */ int ca_count; /* Number of items in pid list. */ struct cpidhead ca_pid; /* Head of the PID list. */ LIST_ENTRY(childaddr) ca_entry; /* Glue to the other list elements. */ }; /* * This hash keeps a number of pointers to `ciphead' lists. * Use the iphash() function to find the proper element of this array * for the records related to an IP address. */ struct ciphead *ciphash[UINT16_MAX]; static unsigned short iphash(struct in_addr *paddr); static struct childaddr *cip_find(struct ciphead *ph, struct in_addr *addr); static struct childaddr *cip_add(struct ciphead *ph, struct in_addr *addr); static struct childpid *cpid_find(struct cpidhead *ph, pid_t pid); static struct childpid *cpid_add(struct childaddr *pa, pid_t pid); int main(void) { struct in_addr lo; struct childaddr *pa; struct childpid *pp; uint16_t hval; /* Add the address of localhost to the proper place in ciphash[]. */ lo.s_addr = htonl(0x7f000001); hval = iphash(&lo); if (ciphash[hval] == NULL) { ciphash[hval] = malloc(sizeof(struct ciphead)); if (ciphash[hval] == NULL) exit(1); } else LIST_INIT(ciphash[hval]); pa = cip_find(ciphash[hval], &lo); if (pa == NULL && (pa = cip_add(ciphash[hval], &lo)) == NULL) { if (LIST_FIRST(ciphash[hval]) == NULL) free(ciphash[hval]); exit(1); } /* Add the PID to the list `pa->ca_pid'. */ cpid_add(pa, getpid()); /* Print the mess we created so far. */ printf("%p: struct ciphead {\n", ciphash[hval]); printf(" lh_first = %p,\n", pa = LIST_FIRST((ciphash[hval]))); printf("};\n"); printf("\n"); printf("%p: struct childaddr {\n", pa); printf(" ca_addr = 0x%08x,\n", (pa->ca_addr).s_addr); printf(" ca_count = %d,\n", pa->ca_count); printf(" ca_pid = %p,\n", &(pa->ca_pid)); printf("};\n"); printf("\n"); printf("%p: struct cpidhead {\n", &(pa->ca_pid)); printf(" lh_first = %p,\n", pp = LIST_FIRST((&(pa->ca_pid)))); printf("};\n"); printf("\n"); printf("%p: struct childpid {\n", pp); printf(" pid = %d,\n", pp->cp_pid); printf("};\n"); printf("\n"); return (0); } /* * Return a very simple XOR-based hash value, derived from the bytes of a * `struct in_addr' structure. */ static uint16_t iphash(struct in_addr *paddr) { uint16_t *sp; uint16_t val; size_t len; size_t k; assert(paddr != NULL); sp = ((uint16_t *) paddr); val = 0; len = sizeof(struct in_addr) / sizeof(uint16_t); if (len == 0 || len == 1) { val = 0xffff; } else { for (k = 0; k < len; k++) val ^= sp[k]; val &= 0xffff; } return (val); } /* * Look in all the elements of `ph' and see if they match `addr'. * Return the address of the first match, or NULL if none is found. */ static struct childaddr * cip_find(struct ciphead *ph, struct in_addr *addr) { struct childaddr *pa; assert(ph != NULL && addr != NULL); LIST_FOREACH(pa, ph, ca_entry) if ((pa->ca_addr).s_addr == (*addr).s_addr) return (pa); return (NULL); } /* * Add a new address structure, in the list of childaddr's pointed at by * the `ph' list head. This doesn't check for an existing match, so * duplicates might end up in your list, if you don't use cip_find() first to * look for older matches. */ struct childaddr * cip_add(struct ciphead *ph, struct in_addr *addr) { struct childaddr *pa; assert(ph != NULL && addr != NULL); /* Try to allocate a new childaddr record. */ if ((pa = malloc(sizeof(struct childaddr))) == NULL) return (NULL); pa->ca_addr = *addr; pa->ca_count = 0; LIST_INIT(&(pa->ca_pid)); LIST_INSERT_HEAD(ph, pa, ca_entry); return (pa); } /* * Look in the list of childpid records pointed at by `ph' for the given PID. * Return a pointer to the proper (struct childpid) or NULL if a match can not * be found at all. */ static struct childpid * cpid_find(struct cpidhead *ph, pid_t pid) { struct childpid *p; assert(ph != NULL); LIST_FOREACH(p, ph, cp_entry) if (p->cp_pid == pid) return (p); return (NULL); } /* * Add a new PID to the list of process IDs help under `pa'. */ static struct childpid * cpid_add(struct childaddr *pa, pid_t pid) { struct childpid *pp; struct cpidhead *ph; assert(pa != NULL); ph = &(pa->ca_pid); pp = cpid_find(ph, pid); if (pp == NULL) { pp = malloc(sizeof(struct childpid)); if (pp == NULL) return (NULL); pp->cp_pid = pid; LIST_INSERT_HEAD(ph, pp, cp_entry); pa->ca_count++; return pp; } return (NULL); } %%% --5I6of5zJg18YgZEa Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.7 (FreeBSD) iD8DBQE9Em9w1g+UGjGGA7YRAif6AJ49abLA7PiNVdEGmJ1xyKPOcCtWrgCfY1D0 rhAqNdnQW2ITgQvXZ+N0x+w= =x+Yz -----END PGP SIGNATURE----- --5I6of5zJg18YgZEa-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020621001233.GB2178>