From owner-freebsd-hackers Thu Jun 20 17:13: 2 2002 Delivered-To: freebsd-hackers@freebsd.org Received: from mailsrv.otenet.gr (mailsrv.otenet.gr [195.170.0.5]) by hub.freebsd.org (Postfix) with ESMTP id C7A7E37B40C for ; Thu, 20 Jun 2002 17:12:37 -0700 (PDT) Received: from hades.hell.gr (patr530-b140.otenet.gr [212.205.244.148]) by mailsrv.otenet.gr (8.12.3/8.12.3) with ESMTP id g5L0CYMW018370 for ; Fri, 21 Jun 2002 03:12:35 +0300 (EEST) Received: from hades.hell.gr (hades [127.0.0.1]) by hades.hell.gr (8.12.4/8.12.4) with ESMTP id g5L0CYLa002291 for ; Fri, 21 Jun 2002 03:12:34 +0300 (EEST) (envelope-from keramida@FreeBSD.org) Received: (from charon@localhost) by hades.hell.gr (8.12.4/8.12.4/Submit) id g5L0CXb0002290 for hackers@FreeBSD.ORG; Fri, 21 Jun 2002 03:12:33 +0300 (EEST) (envelope-from keramida@FreeBSD.org) Date: Fri, 21 Jun 2002 03:12:33 +0300 From: Giorgos Keramidas To: hackers@FreeBSD.org Subject: Re: Limiting clients per source IP address (ftpd, inetd, etc.) Message-ID: <20020621001233.GB2178@hades.hell.gr> References: <20020621000924.GA2178@hades.hell.gr> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="5I6of5zJg18YgZEa" Content-Disposition: inline In-Reply-To: <20020621000924.GA2178@hades.hell.gr> Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG --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 > 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 #include #include #include #include #include #include #include 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