Пример #1
0
struct ccn_charbuf* CcnH_signForwardingEntry(struct ccn* ccnh, CCNDID ccndid, struct ccn_forwarding_entry* fe) {
	struct ccn_charbuf* request = ccn_charbuf_create();
	ccnb_append_forwarding_entry(request, fe);
	struct ccn_charbuf* emptyname = ccn_charbuf_create();
	ccn_name_init(emptyname);
	struct ccn_charbuf* signed_request = ccn_charbuf_create();
	ccn_sign_content(ccnh, signed_request, emptyname, NULL, request->buf, request->length);

	struct ccn_charbuf* reqname = ccn_charbuf_create();
	ccn_name_from_uri(reqname, "ccnx:/ccnx");
	ccn_name_append(reqname, ccndid, CCNDID_length);
	ccn_name_append_str(reqname, fe->action);
	ccn_name_append(reqname, signed_request->buf, signed_request->length);

	ccn_charbuf_destroy(&request);
	ccn_charbuf_destroy(&emptyname);
	ccn_charbuf_destroy(&signed_request);
	return reqname;
}
Пример #2
0
// creates a full structure without action, if proto == "face" only the
// faceid (from cmd_host parameter) and lifetime will be filled in.
struct ccn_face_instance *
parse_ccn_face_instance(struct ccndc_data *self,
                        const char *cmd_proto,
                        const char *cmd_host,     const char *cmd_port,
                        const char *cmd_mcastttl, const char *cmd_mcastif,
                        int freshness)
{
    struct ccn_face_instance *entry;
    struct addrinfo hints = {.ai_family = AF_UNSPEC, .ai_flags = (AI_ADDRCONFIG)};
    struct addrinfo mcasthints = {.ai_family = AF_UNSPEC, .ai_flags = (AI_ADDRCONFIG | AI_NUMERICHOST)};
    struct addrinfo *raddrinfo = NULL;
    struct addrinfo *mcastifaddrinfo = NULL;
    char rhostnamebuf [NI_MAXHOST];
    char rhostportbuf [NI_MAXSERV];
    int off_address = -1, off_port = -1, off_source_address = -1;
    int res;
    int socktype;
    
    entry = calloc(1, sizeof(*entry));
    if (entry == NULL) {
        ccndc_warn(__LINE__, "Fatal error: memory allocation failed");
        goto ExitOnError;
    }
    // allocate storage for Face data
    entry->store = ccn_charbuf_create();
    if (entry->store == NULL) {
        ccndc_warn(__LINE__, "Fatal error: memory allocation failed");
        goto ExitOnError;
    }
    // copy static info
    entry->ccnd_id = (const unsigned char *)self->ccnd_id;
    entry->ccnd_id_size = self->ccnd_id_size;
    
    if (cmd_proto == NULL) {
        ccndc_warn(__LINE__, "command error, missing address type\n");
        goto ExitOnError;
    }
    if (strcasecmp(cmd_proto, "udp") == 0) {
        entry->descr.ipproto = IPPROTO_UDP;
        socktype = SOCK_DGRAM;
    } else if (strcasecmp(cmd_proto, "tcp") == 0) {
        entry->descr.ipproto = IPPROTO_TCP;
        socktype = SOCK_STREAM;
    } else if (strcasecmp(cmd_proto, "face") == 0) {
        errno = 0;
        unsigned long faceid = strtoul(cmd_host, (char **)NULL, 10);
        if (errno == ERANGE || errno == EINVAL || faceid > UINT_MAX || faceid == 0) {
            ccndc_warn(__LINE__, "command error, face number invalid or out of range '%s'\n", cmd_host);
            goto ExitOnError;
        }
        entry->faceid = (unsigned) faceid;
        entry->lifetime = freshness;
        return (entry);
    } else {
        ccndc_warn(__LINE__, "command error, unrecognized address type '%s'\n", cmd_proto);
        goto ExitOnError;
    }
    
    if (cmd_host == NULL) {
        ccndc_warn(__LINE__, "command error, missing hostname\n");
        goto ExitOnError;
    }
    
    if (cmd_port == NULL || cmd_port[0] == 0)
        cmd_port = CCN_DEFAULT_UNICAST_PORT;
    
    hints.ai_socktype = socktype;
    res = getaddrinfo(cmd_host, cmd_port, &hints, &raddrinfo);
    if (res != 0 || raddrinfo == NULL) {
        ccndc_warn(__LINE__, "command error, getaddrinfo for host [%s] port [%s]: %s\n", cmd_host, cmd_port, gai_strerror(res));
        goto ExitOnError;
    }
    res = getnameinfo(raddrinfo->ai_addr, raddrinfo->ai_addrlen,
                      rhostnamebuf, sizeof(rhostnamebuf),
                      rhostportbuf, sizeof(rhostportbuf),
                      NI_NUMERICHOST | NI_NUMERICSERV);
    freeaddrinfo(raddrinfo);
    if (res != 0) {
        ccndc_warn(__LINE__, "command error, getnameinfo: %s\n", gai_strerror(res));
        goto ExitOnError;
    }
    
    off_address = entry->store->length;
    res = ccn_charbuf_append(entry->store, rhostnamebuf, strlen(rhostnamebuf)+1);
    if (res != 0) {
        ccndc_warn(__LINE__, "Cannot append to charbuf");
        goto ExitOnError;
    }
    
    off_port = entry->store->length;
    res = ccn_charbuf_append(entry->store, rhostportbuf, strlen(rhostportbuf)+1);
    if (res != 0) {
        ccndc_warn(__LINE__, "Cannot append to charbuf");
        goto ExitOnError;
    }
    
    entry->descr.mcast_ttl = -1;
    if (cmd_mcastttl != NULL) {
        char *endptr;
        entry->descr.mcast_ttl = strtol(cmd_mcastttl, &endptr, 10); 
        if ((endptr != &cmd_mcastttl[strlen(cmd_mcastttl)]) ||
            entry->descr.mcast_ttl < 0 || entry->descr.mcast_ttl > 255) {
            ccndc_warn(__LINE__, "command error, invalid multicast ttl: %s\n", cmd_mcastttl);
            goto ExitOnError;
        }
    }
    
    if (cmd_mcastif != NULL) {
        res = getaddrinfo(cmd_mcastif, NULL, &mcasthints, &mcastifaddrinfo);
        if (res != 0) {
            ccndc_warn(__LINE__, "command error, incorrect multicat interface [%s]: "
                       "mcastifaddr getaddrinfo: %s\n", cmd_mcastif, gai_strerror(res));
            goto ExitOnError;
        }
        
        res = getnameinfo(mcastifaddrinfo->ai_addr, mcastifaddrinfo->ai_addrlen,
                          rhostnamebuf, sizeof(rhostnamebuf),
                          NULL, 0,
                          NI_NUMERICHOST | NI_NUMERICSERV);
        freeaddrinfo(mcastifaddrinfo);
        if (res != 0) {
            ccndc_warn(__LINE__, "command error, getnameinfo: %s\n", gai_strerror(res));
            goto ExitOnError;
        }
        
        off_source_address = entry->store->length;
        res = ccn_charbuf_append(entry->store, rhostnamebuf, strlen(rhostnamebuf)+1);
        if (res != 0) {
            ccndc_warn(__LINE__, "Cannot append to charbuf");
            goto ExitOnError;
        }
    }
    
    entry->descr.address = (const char *)(entry->store->buf + off_address);
    entry->descr.port = (const char *)(entry->store->buf + off_port);
    if (off_source_address >= 0) {
        entry->descr.source_address = (const char *)(entry->store->buf + off_source_address);
    }
    
    entry->lifetime = freshness;
    
    return entry;
    
ExitOnError:
    ccn_face_instance_destroy(&entry);
    return (NULL);
}

struct ccn_face_instance *
parse_ccn_face_instance_from_face(struct ccndc_data *self,
                                  const char *cmd_faceid)
{
    struct ccn_face_instance *entry = calloc(1, sizeof(*entry));
    
    // allocate storage for Face data
    entry->store = ccn_charbuf_create();
    
    // copy static info
    entry->ccnd_id = (const unsigned char *)self->ccnd_id;
    entry->ccnd_id_size = self->ccnd_id_size;
    
    /* destroy a face - the URI field will hold the face number */
    if (cmd_faceid == NULL) {
        ccndc_warn(__LINE__, "command error, missing face number for destroyface\n");
        goto ExitOnError;
    }
    
    char *endptr;
    int facenumber = strtol(cmd_faceid, &endptr, 10);
    if ((endptr != &cmd_faceid[strlen(cmd_faceid)]) ||
        facenumber < 0) {
        ccndc_warn(__LINE__, "command error invalid face number for destroyface: %d\n", facenumber);
        goto ExitOnError;
    }
    
    entry->faceid = facenumber;
    
    return entry;
    
ExitOnError:
    ccn_face_instance_destroy(&entry);
    return (NULL);
}



///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// "private section
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

int
ccndc_get_ccnd_id(struct ccndc_data *self)
{
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *resultbuf = NULL;
    struct ccn_parsed_ContentObject pcobuf = {0};
    char ccndid_uri[] = "ccnx:/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY";
    const unsigned char *ccndid_result;
    int res = 0;
    
    name = ccn_charbuf_create();
    if (name == NULL) {
        ccndc_warn(__LINE__, "Unable to allocate storage for service locator name charbuf\n");
        return -1;
    }
    
    resultbuf = ccn_charbuf_create();
    if (resultbuf == NULL) {
        ccndc_warn(__LINE__, "Unable to allocate storage for result charbuf");
        res = -1;
        goto Cleanup;
    }
    
    res = ccn_name_from_uri(name, ccndid_uri);
    if (res < 0) {
        ccndc_warn(__LINE__, "Unable to parse service locator URI for ccnd key");
        goto Cleanup;
    }
    
    res = ccn_get(self->ccn_handle,
                  name,
                  self->local_scope_template,
                  4500, resultbuf, &pcobuf, NULL, 0);
    if (res < 0) {
        ccndc_warn(__LINE__, "Unable to get key from ccnd");
        goto Cleanup;
    }
    
    res = ccn_ref_tagged_BLOB (CCN_DTAG_PublisherPublicKeyDigest,
                               resultbuf->buf,
                               pcobuf.offset[CCN_PCO_B_PublisherPublicKeyDigest],
                               pcobuf.offset[CCN_PCO_E_PublisherPublicKeyDigest],
                               &ccndid_result, &self->ccnd_id_size);
    if (res < 0) {
        ccndc_warn(__LINE__, "Unable to parse ccnd response for ccnd id");
        goto Cleanup;
    }
    
    if (self->ccnd_id_size > sizeof (self->ccnd_id))
    {
        ccndc_warn(__LINE__, "Incorrect size for ccnd id in response");
        goto Cleanup;
    }
    
    memcpy(self->ccnd_id, ccndid_result, self->ccnd_id_size);
    
Cleanup:
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&resultbuf);
    return (res);
}


struct ccn_face_instance *
ccndc_do_face_action(struct ccndc_data *self,
                     const char *action,
                     struct ccn_face_instance *face_instance)
{
    struct ccn_charbuf *newface = NULL;
    struct ccn_charbuf *signed_info = NULL;
    struct ccn_charbuf *temp = NULL;
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *resultbuf = NULL;
    struct ccn_parsed_ContentObject pcobuf = {0};
    struct ccn_face_instance *new_face_instance = NULL;
    const unsigned char *ptr = NULL;
    size_t length = 0;
    int res = 0;
    
    face_instance->action = action;
    
    /* Encode the given face instance */
    newface = ccn_charbuf_create();
    ON_NULL_CLEANUP(newface);
    ON_ERROR_CLEANUP(ccnb_append_face_instance(newface, face_instance));
    
    temp = ccn_charbuf_create();
    ON_NULL_CLEANUP(temp);
    res = ccn_sign_content(self->ccn_handle, temp, self->no_name, NULL, newface->buf, newface->length);
    ON_ERROR_CLEANUP(res);
    resultbuf = ccn_charbuf_create();
    ON_NULL_CLEANUP(resultbuf);
    
    /* Construct the Interest name that will create the face */
    name = ccn_charbuf_create();
    ON_NULL_CLEANUP(name);
    ON_ERROR_CLEANUP(ccn_name_init(name));
    ON_ERROR_CLEANUP(ccn_name_append_str(name, "ccnx"));
    ON_ERROR_CLEANUP(ccn_name_append(name, face_instance->ccnd_id, face_instance->ccnd_id_size));
    ON_ERROR_CLEANUP(ccn_name_append_str(name, face_instance->action));
    ON_ERROR_CLEANUP(ccn_name_append(name, temp->buf, temp->length));
    
    res = ccn_get(self->ccn_handle, name, self->local_scope_template, 1000, resultbuf, &pcobuf, NULL, 0);
    ON_ERROR_CLEANUP(res);
    
    ON_ERROR_CLEANUP(ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length));
    new_face_instance = ccn_face_instance_parse(ptr, length);
    ON_NULL_CLEANUP(new_face_instance);
    ccn_charbuf_destroy(&newface);
    ccn_charbuf_destroy(&signed_info);
    ccn_charbuf_destroy(&temp);
    ccn_charbuf_destroy(&resultbuf);
    ccn_charbuf_destroy(&name);
    return (new_face_instance);
    
Cleanup:
    ccn_charbuf_destroy(&newface);
    ccn_charbuf_destroy(&signed_info);
    ccn_charbuf_destroy(&temp);
    ccn_charbuf_destroy(&resultbuf);
    ccn_charbuf_destroy(&name);
    ccn_face_instance_destroy(&new_face_instance);
    return (NULL);
}

int
ccndc_do_prefix_action(struct ccndc_data *self,
                       const char *action,
                       struct ccn_forwarding_entry *forwarding_entry)
{
    struct ccn_charbuf *temp = NULL;
    struct ccn_charbuf *resultbuf = NULL;
    struct ccn_charbuf *signed_info = NULL;
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *prefixreg = NULL;
    struct ccn_parsed_ContentObject pcobuf = {0};
    struct ccn_forwarding_entry *new_forwarding_entry = NULL;
    
    const unsigned char *ptr = NULL;
    size_t length = 0;
    int res;
    
    forwarding_entry->action = action;
    
    prefixreg = ccn_charbuf_create();
    ON_NULL_CLEANUP(prefixreg);
    ON_ERROR_CLEANUP(ccnb_append_forwarding_entry(prefixreg, forwarding_entry));
    temp = ccn_charbuf_create();
    ON_NULL_CLEANUP(temp);
    res = ccn_sign_content(self->ccn_handle, temp, self->no_name, NULL, prefixreg->buf, prefixreg->length);
    ON_ERROR_CLEANUP(res);    
    resultbuf = ccn_charbuf_create();
    ON_NULL_CLEANUP(resultbuf);
    name = ccn_charbuf_create();
    ON_ERROR_CLEANUP(ccn_name_init(name));
    ON_ERROR_CLEANUP(ccn_name_append_str(name, "ccnx"));
    ON_ERROR_CLEANUP(ccn_name_append(name, forwarding_entry->ccnd_id, forwarding_entry->ccnd_id_size));
    ON_ERROR_CLEANUP(ccn_name_append_str(name, forwarding_entry->action));
    ON_ERROR_CLEANUP(ccn_name_append(name, temp->buf, temp->length));
    res = ccn_get(self->ccn_handle, name, self->local_scope_template, 1000, resultbuf, &pcobuf, NULL, 0);
    ON_ERROR_CLEANUP(res);
    ON_ERROR_CLEANUP(ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length));
    new_forwarding_entry = ccn_forwarding_entry_parse(ptr, length);
    ON_NULL_CLEANUP(new_forwarding_entry);
    
    res = new_forwarding_entry->faceid;
    
    ccn_forwarding_entry_destroy(&new_forwarding_entry);
    ccn_charbuf_destroy(&signed_info);
    ccn_charbuf_destroy(&temp);
    ccn_charbuf_destroy(&resultbuf);
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&prefixreg);
    
    return (res);
    
    /* This is where ON_ERROR_CLEANUP sends us in case of an error
     * and we must free any storage we allocated before returning.
     */
Cleanup:
    ccn_charbuf_destroy(&signed_info);
    ccn_charbuf_destroy(&temp);
    ccn_charbuf_destroy(&resultbuf);
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&prefixreg);
    
    return (-1);
}
Пример #3
0
/**
 * 
 * Bind a prefix to a face
 *
 */
static int 
register_unregister_prefix(struct ccn *h, struct ccn_charbuf *local_scope_template,
        struct ccn_charbuf *no_name, struct ccn_charbuf *name_prefix,
        struct ccn_face_instance *face_instance, int operation)
{
	struct ccn_charbuf *temp = NULL;
	struct ccn_charbuf *resultbuf = NULL;
	struct ccn_charbuf *signed_info = NULL;
	struct ccn_charbuf *name = NULL;
	struct ccn_charbuf *prefixreg = NULL;
	struct ccn_parsed_ContentObject pcobuf = {0};
	struct ccn_forwarding_entry forwarding_entry_storage = {0};
	struct ccn_forwarding_entry *forwarding_entry = &forwarding_entry_storage;
	struct ccn_forwarding_entry *new_forwarding_entry;
	const unsigned char *ptr = NULL;
	size_t length = 0;
	int res;

	/* Register or unregister the prefix */
	forwarding_entry->action = (operation == OP_REG) ? "prefixreg" : "unreg";
	forwarding_entry->name_prefix = name_prefix;
	forwarding_entry->ccnd_id = face_instance->ccnd_id;
	forwarding_entry->ccnd_id_size = face_instance->ccnd_id_size;
	forwarding_entry->faceid = face_instance->faceid;
	forwarding_entry->flags = -1;
	forwarding_entry->lifetime = 2100;

	prefixreg = ccn_charbuf_create();
	ccnb_append_forwarding_entry(prefixreg, forwarding_entry);
	temp = ccn_charbuf_create();
	res = ccn_sign_content(h, temp, no_name, NULL, prefixreg->buf, prefixreg->length);
	resultbuf = ccn_charbuf_create();

	/* construct Interest containing prefixreg request */
	name = ccn_charbuf_create();
	ccn_name_init(name);
	ccn_name_append_str(name, "ccnx");
	ccn_name_append(name, face_instance->ccnd_id, face_instance->ccnd_id_size);
	ccn_name_append_str(name, (operation == OP_REG) ? "prefixreg" : "unreg");
	ccn_name_append(name, temp->buf, temp->length);

	/* send Interest, get Data */
	res = ccn_get(h, name, local_scope_template, 1000, resultbuf, &pcobuf, NULL, 0);
	ON_ERROR_CLEANUP(res);

	res = ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length);
	ON_ERROR_CLEANUP(res);
    
	/* extract new forwarding entry from Data */
	new_forwarding_entry = ccn_forwarding_entry_parse(ptr, length);
	ON_NULL_CLEANUP(new_forwarding_entry);

	res = new_forwarding_entry->faceid;

	ccn_forwarding_entry_destroy(&new_forwarding_entry);
	ccn_charbuf_destroy(&signed_info);
	ccn_charbuf_destroy(&temp);
	ccn_charbuf_destroy(&resultbuf);
	ccn_charbuf_destroy(&name);
	ccn_charbuf_destroy(&prefixreg);

	return res;

	cleanup:
		ccn_forwarding_entry_destroy(&new_forwarding_entry);
		ccn_charbuf_destroy(&signed_info);
		ccn_charbuf_destroy(&temp);
		ccn_charbuf_destroy(&resultbuf);
		ccn_charbuf_destroy(&name);
		ccn_charbuf_destroy(&prefixreg);

	return -1;
}
Пример #4
0
int
main(int argc, char **argv)
{
    struct ccn *h = NULL;
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *null_name = NULL;
    struct ccn_charbuf *name_prefix = NULL;
    struct ccn_charbuf *newface = NULL;
    struct ccn_charbuf *prefixreg = NULL;
    struct ccn_charbuf *resultbuf = NULL;
    struct ccn_charbuf *temp = NULL;
    struct ccn_charbuf *templ = NULL;
    const unsigned char *ptr = NULL;
    size_t length = 0;
    const char *arg = NULL;
    const char *progname = NULL;
    struct ccn_parsed_ContentObject pcobuf = {0};
    struct ccn_face_instance face_instance_storage = {0};
    struct ccn_face_instance *face_instance = &face_instance_storage;
    struct ccn_forwarding_entry forwarding_entry_storage = {0};
    struct ccn_forwarding_entry *forwarding_entry = &forwarding_entry_storage;
    struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
    struct ccn_charbuf *keylocator_templ = NULL;
    struct ccn_keystore *keystore = NULL;
    long expire = -1;
    int ipproto;
    unsigned char ccndid_storage[32] = {0};
    const unsigned char *ccndid = NULL;
    size_t ccndid_size = 0;
    int res;
    int opt;

    progname = argv[0];
    while ((opt = getopt(argc, argv, "h")) != -1) {
        switch (opt) {
        case 'h':
        default:
            usage(progname);
        }
    }

    /* Sanity check the URI and argument count */
    arg = argv[optind];
    if (arg == NULL)
        usage(progname);
    name = ccn_charbuf_create();
    res = ccn_name_from_uri(name, arg);
    if (res < 0) {
        fprintf(stderr, "%s: bad ccn URI: %s\n", progname, arg);
        exit(1);
    }
    if (argc - optind < 3 || argc - optind > 4)
        usage(progname);

    h = ccn_create();
    res = ccn_connect(h, NULL);
    if (res < 0) {
        ccn_perror(h, "ccn_connect");
        exit(1);
    }

    newface = ccn_charbuf_create();
    temp = ccn_charbuf_create();
    templ = ccn_charbuf_create();
    keylocator_templ = ccn_charbuf_create();

    resultbuf = ccn_charbuf_create();
    name_prefix = ccn_charbuf_create();
    null_name = ccn_charbuf_create();
    CHKRES(ccn_name_init(null_name));

    keystore = ccn_keystore_create();

    /* We need to figure out our local ccnd's CCIDID */
    /* Set up our Interest template to indicate scope 1 */
    ccn_charbuf_reset(templ);
    ccnb_element_begin(templ, CCN_DTAG_Interest);
    ccnb_element_begin(templ, CCN_DTAG_Name);
    ccnb_element_end(templ);	/* </Name> */
    ccnb_tagged_putf(templ, CCN_DTAG_Scope, "1");
    ccnb_element_end(templ);	/* </Interest> */

    ccn_charbuf_reset(name);
    CHKRES(res = ccn_name_from_uri(name, "ccnx:/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY"));
    CHKRES(res = ccn_get(h, name, templ, 200, resultbuf, &pcobuf, NULL, 0));
    res = ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest,
                              resultbuf->buf,
                              pcobuf.offset[CCN_PCO_B_PublisherPublicKeyDigest],
                              pcobuf.offset[CCN_PCO_E_PublisherPublicKeyDigest],
                              &ccndid, &ccndid_size);
    CHKRES(res);
    if (ccndid_size > sizeof(ccndid_storage))
        CHKRES(-1);
    memcpy(ccndid_storage, ccndid, ccndid_size);
    ccndid = ccndid_storage;

    face_instance->action = "newface";
    face_instance->ccnd_id = ccndid;
    face_instance->ccnd_id_size = ccndid_size;
    if (strcmp(argv[optind + 1], "tcp") == 0)
        ipproto = 6;
    else if (strcmp(argv[optind + 1], "udp") == 0)
        ipproto = 17;
    else
        ipproto = atoi(argv[optind + 1]);
    face_instance->descr.ipproto = ipproto; // XXX - 6 = tcp or 17 = udp
    face_instance->descr.address = argv[optind + 2];
    face_instance->descr.port = argv[optind + 3];
    if (face_instance->descr.port == NULL)
        face_instance->descr.port = CCN_DEFAULT_UNICAST_PORT;
    face_instance->descr.mcast_ttl = -1;
    face_instance->lifetime = (~0U) >> 1;

    CHKRES(res = ccnb_append_face_instance(newface, face_instance));
    temp->length = 0;
    CHKRES(ccn_charbuf_putf(temp, "%s/.ccnx/.ccnx_keystore", getenv("HOME")));
    res = ccn_keystore_init(keystore,
                            ccn_charbuf_as_string(temp),
                            "Th1s1sn0t8g00dp8ssw0rd.");
    CHKRES(res);

    ccnb_element_begin(keylocator_templ, CCN_DTAG_SignedInfo);
    ccnb_element_begin(keylocator_templ, CCN_DTAG_KeyLocator);
    ccnb_element_begin(keylocator_templ, CCN_DTAG_Key);
    CHKRES(ccn_append_pubkey_blob(keylocator_templ, ccn_keystore_public_key(keystore)));
    ccnb_element_end(keylocator_templ);	/* </Key> */
    ccnb_element_end(keylocator_templ);	/* </KeyLocator> */
    ccnb_element_end(keylocator_templ);    /* </SignedInfo> */
    sp.template_ccnb = keylocator_templ;
    sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR;
    sp.freshness = expire;
    ccn_charbuf_reset(temp);
    res = ccn_sign_content(h, temp, null_name, &sp,
                           newface->buf, newface->length);
    CHKRES(res);

    /* Create the new face */
    CHKRES(ccn_name_init(name));
    CHKRES(ccn_name_append_str(name, "ccnx"));
    CHKRES(ccn_name_append(name, ccndid, ccndid_size));
    CHKRES(ccn_name_append(name, "newface", 7));
    CHKRES(ccn_name_append(name, temp->buf, temp->length));
    res = ccn_get(h, name, templ, 1000, resultbuf, &pcobuf, NULL, 0);
    if (res < 0) {
        fprintf(stderr, "no response from face creation request\n");
        exit(1);
    }
    ptr = resultbuf->buf;
    length = resultbuf->length;
    res = ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length);
    CHKRES(res);
    face_instance = ccn_face_instance_parse(ptr, length);
    if (face_instance == NULL)
        CHKRES(res = -1);
    CHKRES(face_instance->faceid);

    /* Finally, register the prefix */
    ccn_charbuf_reset(name_prefix);
    CHKRES(ccn_name_from_uri(name_prefix, arg));
    forwarding_entry->action = "prefixreg";
    forwarding_entry->name_prefix = name_prefix;
    forwarding_entry->ccnd_id = ccndid;
    forwarding_entry->ccnd_id_size = ccndid_size;
    forwarding_entry->faceid = face_instance->faceid;
    forwarding_entry->flags = -1; /* let ccnd decide */
    forwarding_entry->lifetime = (~0U) >> 1;
    prefixreg = ccn_charbuf_create();
    CHKRES(res = ccnb_append_forwarding_entry(prefixreg, forwarding_entry));
    ccn_charbuf_reset(temp);
    res = ccn_sign_content(h, temp, null_name, &sp,
                           prefixreg->buf, prefixreg->length);
    CHKRES(res);
    CHKRES(ccn_name_init(name));
    CHKRES(ccn_name_append_str(name, "ccnx"));
    CHKRES(ccn_name_append(name, ccndid, ccndid_size));
    CHKRES(ccn_name_append_str(name, "prefixreg"));
    CHKRES(ccn_name_append(name, temp->buf, temp->length));
    res = ccn_get(h, name, templ, 1000, resultbuf, &pcobuf, NULL, 0);
    if (res < 0) {
        fprintf(stderr, "no response from prefix registration request\n");
        exit(1);
    }
    fprintf(stderr, "Prefix %s will be forwarded to face %d\n", arg, face_instance->faceid);

    /* We're about to exit, so don't bother to free everything. */
    ccn_destroy(&h);
    exit(res < 0);
}