Código:
dir = malloc(16 * sizeof(char));
Línea 9: Vas a imprimir un error y a salir, no debes usar sprintf porqué nunca se imprimirá el mensaje, usa un printf normal o un fprintf a stderr, si lo prefieres.
Línea 13: sprintf espera un puntero a la cadena, no el contenido del primer elemento. Quita el asterisco a dir. De igual forma revisa las variables que van a construir la cadena, te falta la variable d3 y te sobra una d4.
Línea 20: Los estándares actuales de C esperan que main sea declarada como una función que devuelve un entero. Defínela como int main....
Línea 22: Ya que vas a devolver un puntero con la función necesitas de una variable que lo reciba. Declara una variable tipo puntero a char: por ejemplo char *ip;
Línea 32: Como se ha dicho la función regresa el dato como cadena y debería recibirla la variable que has creado antes: ip = IP(&a, &b, &c, &d);
Línea 33: puts espera que se le de una cadena, no la dirección de una función O_o . Por tanto dale la variable que guarda la cadena: puts(ip);
Línea 34: Una vez que no necesites más un elemento creado dinámicamente debes liberarlo. Hay que acostumbrarse a ello. free(ip);